Wehe

Have you ever wondered if your Internet service provider is slowing down certain apps relative to others? Unfortunately, your mobile device and carriers currently give you little or no way to tell if this is the case. With Wehe, you can test if this is happening to the Internet traffic generated by popular apps.

Wehe uses your device to exchange Internet traffic recorded from real, popular apps like YouTube and Spotify—effectively making it look as if you are using those apps. As a result, if an Internet service provider (ISP) tries to slow down an YouTube, Wehe would see the same behavior. We then send the same app’s Internet traffic, but replacing the content with “bit-inverted bytes”, which prevents the ISPs from classifying the traffic as belonging to the app. Our hypothesis is that the randomized traffic will not cause an ISP to conduct application-specific differentiation (e.g., throttling or blocking), but the original traffic will. We repeat these tests several times to rule out noise from bad network conditions, and tell you at the end whether your ISP is giving different performance to an app’s network traffic.

Source code

Source code for the Wehe server and clients can be found on the Wehe project website.

Citing the M-Lab Wehe Dataset

Please cite this paper for using the Wehe dataset: A large-scale analysis of deployed traffic differentiation practices. https://dl.acm.org/doi/abs/10.1145/3341302.3342092

Policies & Support Information

The Wehe project is led by researchers at Northeastern University and is governed by their privacy policy.

Data Collected by Wehe in Raw Format

Data collected by Wehe while hosted on the M-Lab platform is available in raw formats at https://console.cloud.google.com/storage/browser/archive-measurement-lab/wehe/.

Wehe Data in BigQuery

To make NDT data more readily available for research and analysis, M-Lab parses all WeHe data into BigQuery tables and views, and makes query access available for free by subscription to a Google Group. Find out more about how to get access on our BigQuery QuickStart page.

Note that we sometimes use the terms “table” and “view” interchangeably: they reflect different internal implementations, but due to billing and access controls everything documented here as a table is actually presented as a view.

Note that each WeHe test consists of two replays: a replay of the original application traces and a bit-inverted version of it. Therefore, in some of the tables (ClientXputs1) you will find two rows that belong to the same test. While in others, we only report for one of the two replays to avoid repetitions (ReplayInfo and Decisions1).

The WeHe data has three tables. The userID and historyCount fields together represent a unique id for each WeHe test performed, and can be used to map records between the three tables.

Tables Description
ReplayInfo1 Contains metadata for the user and the test. For example: the time at which the test was performed, the network the user was connected to, the device the user was using, and many more.
ClientXputs1 Contains throughout samples of the replay collected at the client side.
Decisions1 Contains statistics of the Kolmogorov-Smirnov test performed on the throughput samples present in the ClientXputs1 table. A differentiation is reported if all these are true: (1) KSAcceptRatio > 0.95, (2) KSPVal < 0.05 (3) avgXputDiffPct > 0.1.

ReplayInfo_SCHEMA Schema

Field Name Nested Field Nested Field Type Mode Description
timestamp     TIMESTAMP REQUIRED  
userID     STRING REQUIRED  
clientIP     STRING REQUIRED IP Address is truncated to /24
clientIP2     STRING    
replayName     STRING REQUIRED  
extraString     STRING   Extra string sent from the client (not used)
historyCount     INTEGER REQUIRED  
testID     STRING REQUIRED Replay type (0 for original and 1 for bit-inverted replay)
exception     STRING    
testFinished     BOOLEAN    
testFinishedWoutError     BOOLEAN    
iperfInfo     STRING    
testDurationServer     FLOAT   Test length (in seconds) recorded on the server”)
testDurationClient     FLOAT   Test length (in seconds) recorded on the server”)
metadata     RECORD    
  cellInfo   STRING    
  model   STRING    
  manufacturer   STRING    
  carrierName   STRING    
  os   RECORD    
    INCREMENTAL STRING    
    RELEASE STRING    
    SDK_INT INTEGER    
  networkType   STRING    
  locationInfo   RECORD    
    latitude FLOAT    
    longitude FLOAT    
    country STRING    
    countryCode STRING    
    city STRING    
    localTime TIMESTAMP    
  updatedCarrierName   STRING    
emptyBool     BOOLEAN    
clientVersion     STRING    
measurementUUID     STRING    

ClientXputs_SCHEMA

Field Name Type Required Description
userID STRING REQUIRED  
historyCount INTEGER REQUIRED  
testID STRING REQUIRED Replay type (0 for original and 1 for bit-inverted replay)
xputSamples FLOAT REPEATED throughput samples collected at client
intervals FLOAT REPEATED time intervals at which the throughput samples are recorded

Decisions_SCHEMA

Field Nested Field Type Mode Description
userID   STRING REQUIRED  
historyCount   STRING REQUIRED  
testID   STRING REQUIRED Replay type (0 for original and 1 for bit-inverted replay)
avgXputDiffPct   FLOAT   avgXputDiff / max(control’s avgXput, original’s avgXput)
KSAcceptRatio   FLOAT   KS test acceptance ratio
avgXputDiff   FLOAT   control’s avgXput - original’s avgXput
emptyField   STRING   not used anymore
originalXputStats   RECORD    
  max FLOAT    
  min FLOAT    
  average FLOAT    
  median FLOAT    
  std FLOAT    
controlXputStats   RECORD    
  max FLOAT    
  min FLOAT    
  average FLOAT    
  median FLOAT    
  std FLOAT    
minXput   FLOAT    
KSAvgDVal   FLOAT   Average D value of the sampled KS test
KSAvgPVal   FLOAT   Average P value of the sampled KS test
KSDVal   FLOAT   D value of the KS test
KSPVal   FLOAT   P value of the KS test

Sample Queries

Listing tests where differentiation was detected:

WITH info AS (
SELECT raw.*
FROM `measurement-lab.wehe_raw.replayInfo1`
WHERE
(date BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY) AND CURRENT_DATE())
AND NOT (raw.userID LIKE '@%')
AND (raw.metadata.updatedCarrierName like '%(cellular)')
),
result AS (
SELECT raw.*
FROM `measurement-lab.wehe_raw.decisions1`
WHERE
(date BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY) AND CURRENT_DATE())
AND (raw.KSAcceptRatio > 0.95) AND (raw.KSPVal < 0.05) AND (raw.avgXputDiffPct > 0.1)
)
SELECT *
FROM info INNER JOIN result
ON (info.userID = result.userID) AND (info.historyCount = CAST(result.historyCount AS INT64))
LIMIT 1000

Counting the number of total tests performed and the number of tests with differentiation per network:

WITH info AS (
SELECT raw.*
FROM `measurement-lab.wehe_raw.replayInfo1`
WHERE
(date BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY) AND CURRENT_DATE())
AND NOT (raw.userID LIKE '@%')
AND (raw.metadata.updatedCarrierName like '%(cellular)')
),
result AS (
SELECT raw.*
FROM `measurement-lab.wehe_raw.decisions1`
WHERE
(date BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY) AND CURRENT_DATE())
)
SELECT
info.metadata.updatedCarrierName as network,
COUNT(*) as total_nb_tests,
COUNTIF((result.KSAcceptRatio > 0.95) AND (result.KSPVal < 0.05) AND (result.avgXputDiffPct > 0.1)) as nb_tests_with_TD
FROM info INNER JOIN result
ON (info.userID = result.userID) AND (info.historyCount = CAST(result.historyCount AS INT64))
GROUP BY info.metadata.updatedCarrierName
ORDER BY total_nb_tests DESC
LIMIT 1000
Back to Top