JSON Exports API for WiFi data
Before you start exporting WiFi data, it’s critical to understand that in 2024, the vast majority of WiFi probe requests contain randomized MAC addresses.
Less than 10% of probe requests are not being randomized.
This is severly impacting the quality of passive WiFi analytics, regardless of your choice of network equipment or analytics provider.
We strongly recommend to interpret WiFi data as very high level trends and to invest in reliable, privacy respecting solutions like smart cameras.
While the GraphQL API exposes a number of interesting metrics, it wasn’t designed to export raw data efficiently.
This endpoint addresses this use case and allows exporting raw WiFi data.
The endpoint offers 4 variants:
- Version 1 Accepts batches of location IDs (or reference numbers, or zone ID) and rejects queries containing unauthorized IDs.
- Version 2 Accepts batches of location IDs (or reference numbers, or zone ID) and allows partial responses.
- Version 3 Implements a cursor approach. You only need to specify a brand ID and locations will be returned in batches automatically.
- Version 4 Same as V1, but includes all time intervals even when metric values are zero.
Authentication
The authentication workflow is the same as the GraphQL API. Using your client ID and client secret, the following HTTP query will return your token:
curl --request POST \
--url https://tokens.analytiks.ai \
--header 'content-type: application/json' \
--data '{"client_id":"__YOUR_CLIENT_ID__","client_secret":"__YOUR_CLIENT_SECRET__","audience":"https://gql.analytiks.ai","grant_type":"client_credentials"}'
On success the API call will return a structure like this one:
{"access_token":"YOUR_TOKEN","expires_in":86400,"token_type":"Bearer"}
Usage
Once you have your token, you can send POST requests to https://exports.analytiks.ai/wifi/json/v1.
We are expecting the following headers:
Content-Typeset toapplication/jsonAuthorizationset toBearer YOUR_TOKEN
Request body
Here’s an examplre request body.
{
"startDate": "2023-06-08T11:30:00.000Z",
"endDate": "2023-06-08T23:45:00.000Z",
"locations": [1, 2, 3]
}
Dates are ISO 8601 and can be sent either as UTC or local time. A few notes regarding dates:
- If dates are requested in UTC (eg.
2023-06-08T11:30:00.000Z, note the finalZ), dates in the response will also be UTC. - If dates are requested in local time (eg.
2023-06-08T09:00:00.000, no finalZ), dates in the response will also be local time. - Both
startDateandendDatemust be in the same format. - A maximum of 5 days can be requested at once.
A maximum of 50 locations can be requested at once.
Use the GraphQL API to figure out what location IDs you can use in your queries.
You can also request by zone by sending a zoneId (instead of locations / brandId+referenceNumbers).
When requesting by zoneId, the endpoint resolves the owning location and returns the same aggregated metrics for that zone.
{
"startDate": "2023-06-08T11:30:00.000Z",
"endDate": "2023-06-08T23:45:00.000Z",
"zoneId": "11111111-1111-1111-1111-111111111111"
}
In this version of the endpoint, requesting locations you are not allowed to access will cause the whole request to be rejected with a status 401.
A v2 of the endpoint that allows partial results is described at the bottom of the page.
Requests can also be made by reference numbers (which you can set to your internal IDs)
{
"startDate": "2023-06-08T11:30:00.000Z",
"endDate": "2023-06-08T23:45:00.000Z",
"brandId": 1234,
"referenceNumbers": ["US0658", "FR2561"]
}
The same rules apply, except here we expect a brand ID (which does not change) and a list of reference numbers.
In this mode, the response will contain a referenceNumber number fields for each requested location.
Response body
The API can return data for the following metrics. All metrics are Maps from a UTC date to Natural numbers:
visits: People who entered the location (excludesbounces, see below).dwellTime: How long people spent inside the location, in ms.bounces: People who entered, but have not been observed long enough.allVisits: All visitors who entered the location (visits+bounces).walkBys: People who walked past the location, observed with a signal strength too weak to be counted as visitors.newVisitors: People we’re seeing for the first time.returningVisitors: People we’ve seen at least once before.under15Mins: Visitors we’ve observed for less than 15 minutes.from15To30Mins: Visitors we’ve observed for more than 15 minutes, but less than 30.from30To45Mins: Visitors we’ve observed for more than 30 minutes, but less than 45.from45To60Mins: Visitors we’ve observed for more than 45 minutes, but less than an hour.over60Mins: Visitors we’ve observed for an hour or more.
Again, all dates are UTC. A typical response looks like this:
[
{
"locationId": 1,
"visits": {
"2023-06-08T08:00:00Z": 3,
"2023-06-08T09:00:00Z": 6
},
"dwellTime": {
"2023-06-08T14:00:00Z": 111111,
"2023-06-08T15:00:00Z": 111111
},
"newVisitors": {
"2023-06-08T08:00:00Z": 1,
"2023-06-08T09:00:00Z": 2
},
"returningVisitors": {
"2023-06-08T08:00:00Z": 2,
"2023-06-08T09:00:00Z": 4
},
"bounces": {
"2023-06-08T14:00:00Z": 3,
"2023-06-08T15:00:00Z": 9
},
"under15Mins": {
"2023-06-08T14:00:00Z": 10,
"2023-06-08T15:00:00Z": 12
},
"over60Mins": {
"2023-06-08T08:00:00Z": 1
},
}
]
Exports endpoint V2
A variant of the endpoint is available at https://exports.analytiks.ai/wifi/json/v2.
In this version, requesting unauthorized locations by mistake will not cause the whole request to be rejected.
Instead, you’ll get a partial response. To achieve this, the structure of the response must be slightly different:
{
"successes": [...], // Same structure as in V1
"failures": {
"description": "You are not authorized to query these locations",
"locations": [__LOC_ID_1__, ...]
}
}
Some additional information:
- If all requested locations are authorized, the
failuresobject will just be empty. - The request body format is the same as V1 (including
zoneIdsupport). - In case of full or partial response, the HTTP status will be set to 200
- If all requested locations are rejected, the HTTP status will be set to 401
Exports endpoint V3
A third variant of the endpoint is available at https://exports.analytiks.ai/wifi/json/v3.
In this version, batches are done automatically using cursors. You only need to specify a brandId and the endpoint will return batches of data with an optional cursor.
When a cursor is returned in the response, you can include it in your next request to get the next batch.
A cursor set to null means eveything was fetched.
Request body:
{
"startDate": "2023-06-08T11:30:00.000",
"endDate": "2023-06-08T23:45:00.000",
"brandId": 1234,
"cursor": null // Can be null or missing for the first batch
}
Response body:
{
"cursor": "some_opaque_string" // or null when everything has been fetched
"data": [...], // Same structure as in V1
}
Exports endpoint V4
A fourth variant of the endpoint is available at https://exports.analytiks.ai/wifi/json/v4.
V4 is designed for complete time series: the response includes all time intervals in your requested date range, even when the metrics are zero.
Authorization behavior is the same as V1: requesting any unauthorized locations/zone will reject the whole request with HTTP 401.
Request body: The request body format is the same as V1 (manual batch endpoints), and supports locations, brandId+referenceNumbers, or zoneId.
Example request body using zoneId:
{
"startDate": "2023-06-08T11:30:00.000Z",
"endDate": "2023-06-08T23:45:00.000Z",
"zoneId": "11111111-1111-1111-1111-111111111111"
}
Response body: Same structure as V1, but with zero-filled time buckets for every interval in the requested date range.