This article covers the three data endpoints in the Indivd API. Each endpoint returns visitor data for a specified date range and can be scoped using optional parameters. Use the filter endpoints to look up the integer IDs you need before making data requests.
The API exposes two distinct data models. The line-based model (line_crosses) counts directional crossing events at individual camera boundaries. The zone-based model (zone_visitors, drop_in_rate) uses ReID technology to understand visitor behaviour inside defined areas.
The zone-based model enables metrics that line-based counting cannot produce: how long visitors stayed, whether they left immediately, how many were distinct individuals, whether they moved between zones in the same session, and what share of passing foot traffic chose to enter. These metrics, dwell time, bounce rate, unique visits, cross-visitation, and drop-in rate, are what differentiate Indivd from basic people counting systems.
Included in: ✓ Indivd Basic ✓ Indivd Pro ✓ Indivd Complete
Related articles
This article contains the following topics:
- Two data models: line-based and zone-based
- Common behaviour
- Line crosses
- Zone visitors
- Drop-in rate
- Error reference
Two data models: line-based and zone-based
Understanding the difference between the two data models helps you choose the right endpoint and interpret results correctly.
The line-based model is simple and universal. A line is a virtual boundary in a camera's field of view. Every time a person crosses it, the system records one event. There is no memory of that person before or after the crossing. This model is available on all plans and works without ReID.
The zone-based model is richer and requires ReID. A zone is a defined area monitored by one or more cameras. When a visitor enters a zone, the platform uses ReID technology to track that individual anonymously for the duration of their time in the zone, and across other zones in the same location. This makes the following metrics possible:
- Dwell time: how long a visitor spent inside the zone, in seconds
- Bounce rate: the share of visitors who left within a configurable threshold, indicating low engagement
- Unique visits: the number of distinct individuals, as opposed to total entries. A visitor who enters the same zone twice counts as two visits but one unique visit
- Cross-visitation: whether visitors to one zone also visited other zones in the same session, enabling analysis of visitor journeys across a location
- Drop-in rate: the share of people passing a zone entrance who chose to enter, combining passing-by line data with zone entry data
Dwell time, bounce rate, and unique visits are returned by the zone_visitors endpoint and require an Indivd Pro subscription. Drop-in rate is returned by the drop_in_rate endpoint and requires passing-by lines to be configured at your location. Cross-visitation can be derived by comparing unique_visits across zones within the same request.
The line-based endpoint (line_crosses) does not use ReID and does not return any of these metrics. It returns raw crossing counts only.
Common behaviour
All three data endpoints share the following behaviour:
- All requests are GET requests.
- All responses are JSON.
- Authentication is required on every request. See Authentication.
-
start_dateandend_dateare required on every data request. Dates are inyyyy-mm-ddformat. - Optional filter parameters default to returning all available data when omitted. For example, omitting
locationreturns data across all locations your token has access to. - When multiple values are accepted for a single parameter (comma-separated), conditions within that parameter are OR. Conditions between different parameters are AND. For example:
category=1,3andfloor=2,5returns results where category is (1 OR 3) AND floor is (2 OR 5). - If no data matches your filter combination for the requested date range, the API returns a
200response with an empty result set, not an error.
Line crosses
Returns visitor counts at the level of individual counting lines for a specified date range. Results can be grouped and filtered by location, floor, zone, category, or line. Each count represents one crossing event at one line: a visitor who crosses three lines contributes three counts, not one.
GET https://api.indivd.com/api/v1/rnd/insights/external/line_crosses/
Note: Do not request totals across all lines for a location without filtering. A visitor crossing multiple lines is counted once per crossing, not once per visitor. A single person walking through an entrance and past two internal boundaries generates three counts across three lines. Always scope requests to specific zones, categories, or lines to avoid unintentionally aggregating across unrelated lines.
Parameters
| Name | Description | Required |
|---|---|---|
start_date |
String. Date in yyyy-mm-dd format. Start of the requested date range, inclusive. |
Yes |
end_date |
String. Date in yyyy-mm-dd format. End of the requested date range, inclusive. |
Yes |
aggregate_by |
String. Groups results by one of: year, month, dayofmonth, dayofweek, week, hour, minute. Default: determined automatically by date range (see below). Limitations: minute is supported for date ranges of 3 days or fewer only; hour is supported for 7 days or fewer only; week is available within the same calendar year only. |
No |
organization |
Integer ID. Single value only. Default: all organisations your token has access to. | No |
location |
Integer ID. Single value only. Default: all locations. | No |
floor |
Integer. Comma-separated for multiple values. Negative values are supported for basement floors. Default: all floors. | No |
zone_to |
Integer. Comma-separated for multiple values. Filters to lines where the visitor is entering the specified zone. Default: all zones. | No |
zone_from |
Integer. Comma-separated for multiple values. Filters to lines where the visitor is exiting the specified zone. Default: all zones. | No |
category |
Integer. Comma-separated for multiple values. Filters to lines belonging to the specified categories. Default: all categories. | No |
line_ids |
Integer. Comma-separated for multiple values. Filters to specific counting lines by ID. Default: all lines. | No |
Default aggregation when aggregate_by is not set:
- 1 day: hour
- 2 to 31 days: day
- More than 31 days: month
Sample request
curl --location --request GET \ 'https://api.indivd.com/api/v1/rnd/insights/external/line_crosses/?start_date=2025-03-01&end_date=2025-03-02&aggregate_by=dayofmonth' \ --header 'Authorization: Token [your-token-here]'
Sample response
[
{
"_id": {
"year": 2025,
"month": 3,
"dayofmonth": 1
},
"count": 100006
},
{
"_id": {
"year": 2025,
"month": 3,
"dayofmonth": 2
},
"count": 115069
}
]Response fields
| Field | Type | Description |
|---|---|---|
_id |
Object | The aggregation period this row covers. Contains the date or time fields matching your aggregate_by selection (e.g. year, month, dayofmonth). |
count |
Integer | Total number of line crossings in the aggregation period. One visitor crossing multiple lines contributes one count per crossing. |
Zone visitors
The zone_visitors endpoint is the primary zone-based data endpoint. It uses ReID technology to return behavioural metrics for each zone: total visits, unique visits, bounce count, and dwell time statistics. Results are always grouped by zone and by your chosen time interval.
Use this endpoint when you need to understand how visitors behave inside a space, not just how many crossed a boundary. To derive cross-visitation (whether visitors to one zone also appeared in another), request multiple zones in the same call and compare their unique_visits values.
GET https://api.indivd.com/api/v1/rnd/insights/external/zone_visitors/
Note: unique_visits, bounce, dwell_time, and dwell_time_stats require an Indivd Pro subscription. These fields return empty or 0 on Basic plans. Contact your Indivd account contact for plan information.
Parameters
| Name | Description | Required |
|---|---|---|
start_date |
String. Date in yyyy-mm-dd format. Start of the requested date range, inclusive. |
Yes |
end_date |
String. Date in yyyy-mm-dd format. End of the requested date range, inclusive. |
Yes |
comparison_start_date |
String. Date in yyyy-mm-dd format. Use together with comparison_end_date to return two datasets in the same response for period-over-period comparison. The same aggregation applies to both periods. For different aggregations per period, make two separate requests. |
No |
comparison_end_date |
String. Date in yyyy-mm-dd format. Required if comparison_start_date is set. |
No |
aggregate_by |
String. Groups results by one or more comma-separated values: year, month, week, dayofmonth, dayofweek, hour, minute, loc_id. Results are always grouped by zone regardless of this setting. Set aggregate_by=zone to return a single total per zone for the full date range, bypassing time-based intervals. Default: determined automatically by date range (see below). |
No |
location |
Integer ID. Comma-separated for multiple values. Default: all locations. | No |
zones |
Integer. Comma-separated for multiple values. Default: all zones. | No |
bounce_threshold |
Integer, seconds. Overrides the per-zone default bounce threshold. Set to 0 to disable bounce tracking entirely. Set to -1 or omit to use the default threshold configured per zone. Default: zone-level setting. |
No |
min_dwell |
Integer, seconds. Visits shorter than this value are reported in exclude.min_dwell_time in the response. They are not subtracted from the visits total. Default: disabled. |
No |
max_dwell |
Integer, seconds. Maximum: 10800 (3 hours). Visits longer than this value are reported in exclude.max_dwell_time in the response. They are not subtracted from the visits total. Default: no limit. |
No |
tz |
String. Time zone in TZ identifier format. See List of tz database time zones. Default: the time zone of the first location in the request. | No |
Default aggregation when aggregate_by is not set:
- 1 day: hour
- 2 to 31 days: day
- 32 to 364 days: week
- 365 days or more: month
Sample request
curl --location --request GET \ 'https://api.indivd.com/api/v1/rnd/insights/external/zone_visitors/?start_date=2025-03-01&end_date=2025-03-07&location=124&zones=201' \ --header 'Authorization: Token [your-token-here]'
Sample response
{
"current": {
"startdate": "2025-03-01",
"enddate": "2025-03-07",
"insights": [
{
"visits": 284,
"unique_visits": 251,
"bounce": 43,
"dwell_time": 187.5,
"dwell_time_stats": {
"mean": 187.5,
"min": 12.0,
"max": 1843.0,
"quantiles": [95.0, 148.0, 231.0],
"n": 251
},
"exclude": {
"min_dwell_time": 0,
"max_dwell_time": 0
},
"aggregation": {
"dayofmonth": 1,
"month": 3,
"year": 2025,
"zone_id": 201,
"zone_name": "Entrance",
"bounce_threshold": 120
}
}
]
},
"comparison": {}
}To add a comparison period, include comparison_start_date and comparison_end_date in the request. The response will include a populated comparison block with the same structure as current:
curl --location --request GET \ 'https://api.indivd.com/api/v1/rnd/insights/external/zone_visitors/?start_date=2025-03-01&end_date=2025-03-07&location=124&zones=201&comparison_start_date=2025-02-01&comparison_end_date=2025-02-07' \ --header 'Authorization: Token [your-token-here]'
{
"current": {
"startdate": "2025-03-01",
"enddate": "2025-03-07",
"insights": [
{
"visits": 284,
"unique_visits": 251,
"bounce": 43,
"dwell_time": 187.5,
"aggregation": {
"dayofmonth": 1,
"month": 3,
"year": 2025,
"zone_id": 201,
"zone_name": "Entrance",
"bounce_threshold": 120
}
}
]
},
"comparison": {
"startdate": "2025-02-01",
"enddate": "2025-02-07",
"insights": [
{
"visits": 261,
"unique_visits": 234,
"bounce": 38,
"dwell_time": 172.3,
"aggregation": {
"dayofmonth": 1,
"month": 2,
"year": 2025,
"zone_id": 201,
"zone_name": "Entrance",
"bounce_threshold": 120
}
}
]
}
}Note: The same aggregation interval applies to both current and comparison. If you need different intervals for each period, make two separate requests.
Response fields
| Field | Type | Description |
|---|---|---|
current |
Object | Contains the primary dataset. Always present. |
current.startdate |
String | The start date of the requested period, as supplied in the request. |
current.enddate |
String | The end date of the requested period, as supplied in the request. |
current.insights |
Array | One object per time interval per zone. With a 7-day request and daily aggregation, you receive up to seven objects per zone. |
visits |
Integer | Total number of zone entries in the interval. Available on all plans. |
unique_visits |
Integer | Number of distinct visitors identified by re-identification. Requires Indivd Pro. Returns 0 on Basic plans. |
bounce |
Integer | Number of visits shorter than bounce_threshold seconds. Requires Indivd Pro. Returns 0 on Basic plans. |
dwell_time |
Float | Mean time spent in the zone, in seconds. Equivalent to dwell_time_stats.mean. Requires Indivd Pro. Returns 0 on Basic plans. |
dwell_time_stats |
Object | Statistical breakdown of dwell times for visits in the interval. Contains mean, min, max, quantiles, and n. Requires Indivd Pro. Returns empty on Basic plans. |
dwell_time_stats.mean |
Float | Mean dwell time in seconds. |
dwell_time_stats.min |
Float | Shortest dwell time recorded in the interval, in seconds. |
dwell_time_stats.max |
Float | Longest dwell time recorded in the interval, in seconds. |
dwell_time_stats.quantiles |
Array of floats | 25th, 50th, and 75th percentile dwell times in seconds, in that order. |
dwell_time_stats.n |
Integer | Number of visits included in the dwell time calculation. Visits filtered out by min_dwell or max_dwell are not counted here. |
exclude.min_dwell_time |
Integer | Number of visits shorter than the min_dwell filter value. These visits are still included in the visits total. Zero if no min_dwell parameter was set. |
exclude.max_dwell_time |
Integer | Number of visits longer than the max_dwell filter value. These visits are still included in the visits total. Zero if no max_dwell parameter was set. |
aggregation |
Object | The time period and zone this row of data covers. Always present. Contains the date or time fields matching your aggregate_by selection, plus zone_id, zone_name, and bounce_threshold. |
aggregation.bounce_threshold |
Integer | The bounce threshold in seconds applied to this row. Reflects either the zone default or the value passed in the bounce_threshold parameter. |
comparison |
Object | Empty unless comparison_start_date and comparison_end_date were included in the request. When populated, has the same structure as current. |
Drop-in rate
Drop-in rate combines both data models. It uses passing-by lines, which are lines placed in the traffic flow outside a zone entrance, to measure how many people walked past, and zone entry lines to measure how many of those people entered. The ratio between the two is the drop-in rate: the conversion rate of passing foot traffic to zone entry.
This endpoint requires a specific camera and line configuration that is not set up by default. Indivd must configure passing-by lines and link them to the relevant zones at your location before this endpoint returns meaningful data.
Returns the share of people passing a zone entrance who entered. Results include a period summary, a time-series breakdown, and a per-zone detail section.
GET https://api.indivd.com/api/v1/rnd/insights/external/drop_in_rate/
Note: Passing-by lines must be configured by Indivd at your location before this endpoint returns data. Contact support@indivd.com to request configuration.
Note: Drop-in rate values can exceed 100%. This occurs when the number of recorded zone entries is higher than the number of recorded passing-by events for the same interval, typically due to timing differences in line configuration or camera coverage overlap. Values above 100% should be treated as a configuration signal rather than a meaningful rate. Contact support@indivd.com if you consistently see values above 100%.
Parameters
| Name | Description | Required |
|---|---|---|
start_date |
String. Date in yyyy-mm-dd format. Start of the requested date range, inclusive. |
Yes |
end_date |
String. Date in yyyy-mm-dd format. End of the requested date range, inclusive. |
Yes |
comparison_start_date |
String. Date in yyyy-mm-dd format. Use together with comparison_end_date to return two datasets in the same response. The same interval applies to both periods. For different intervals per period, make two separate requests. |
No |
comparison_end_date |
String. Date in yyyy-mm-dd format. Required if comparison_start_date is set. |
No |
interval |
String. Groups results by one of: year, month, week, day, hour. Default: determined automatically by date range (see below). |
No |
location |
Integer ID. Comma-separated for multiple values. Recommended: always specify a location to avoid aggregating across an entire organisation. If locations span different time zones, make separate requests per time zone group. Default: all locations. | No |
zone |
Integer. Comma-separated for multiple values. Recommended: always specify individual zones. Without this, the summary and details sections aggregate all zones together, which is rarely useful. The zone_details section always returns per-zone data regardless. Default: all zones. |
No |
Default interval when interval is not set:
- 1 day: hour
- 2 to 31 days: day
- 32 to 364 days: week
- 365 days or more: month
Sample request
curl --location --request GET \ 'https://api.indivd.com/api/v1/rnd/insights/external/drop_in_rate/?start_date=2025-05-15&end_date=2025-05-20&location=124&zone=1121' \ --header 'Authorization: Token [your-token-here]'
Sample response
{
"summary": {
"current": {
"startdate": "2025-05-15",
"enddate": "2025-05-20",
"passing_by": 7497,
"enter": 4532,
"enter_percentage": 60.5
},
"comparison": {}
},
"details": {
"interval": "day",
"current": [
{
"year": 2025, "month": 5, "day": 15,
"passing_by": 1450, "enter": 715, "drop_in_rate": 49.3
},
{
"year": 2025, "month": 5, "day": 16,
"passing_by": 1427, "enter": 757, "drop_in_rate": 53.0
}
],
"comparison": []
},
"zone_details": {
"current": {
"1121": {
"zone_id": 1121,
"zone_name": "Example zone 1",
"loc_id": 124,
"loc_name": "Sample Location - Stockholm",
"location_custom_id": "",
"total_visits": 4532,
"total_passing_by": 7497,
"drop_in_rate": 60.5,
"details": [
{
"year": 2025, "month": 5, "dayofmonth": 15,
"visits": 715, "passing_by": 1450, "drop_in_rate": 49.3
},
{
"year": 2025, "month": 5, "dayofmonth": 16,
"visits": 757, "passing_by": 1427, "drop_in_rate": 53.0
}
]
}
},
"comparison": {}
}
}Response structure
The response contains three sections: summary, details, and zone_details.
summary
A single aggregate for the entire requested period. Use this for a quick headline figure.
| Field | Type | Description |
|---|---|---|
summary.current.startdate |
String | The start date of the requested period. |
summary.current.enddate |
String | The end date of the requested period. |
summary.current.passing_by |
Integer | Total number of passing-by events recorded across all included zones for the period. |
summary.current.enter |
Integer | Total number of zone entries recorded across all included zones for the period. |
summary.current.enter_percentage |
Float | Drop-in rate as a percentage: enter / passing_by × 100. Can exceed 100 in some configurations. See the note above. |
details
A time-series breakdown of the summary data at the requested interval. Aggregates all included zones together.
| Field | Type | Description |
|---|---|---|
details.interval |
String | The interval applied to this response (e.g. day, hour). Reflects your interval parameter or the automatic default. |
details.current |
Array | One object per interval. Each object contains date fields for the interval period, plus passing_by, enter, and drop_in_rate. |
details.current[].drop_in_rate |
Float | Drop-in rate as a percentage for that interval. |
details.comparison |
Array | Empty unless comparison dates were set. When populated, has the same structure as details.current. |
zone_details
Per-zone breakdown. Always present regardless of the zone parameter. The primary section to use when querying multiple zones.
| Field | Type | Description |
|---|---|---|
zone_details.current |
Object | Keyed by zone ID. Each key contains one zone's complete data. |
[zone_id].zone_id |
Integer | The zone ID. |
[zone_id].zone_name |
String | The zone name as configured in the Indivd platform. |
[zone_id].loc_id |
Integer | The location ID this zone belongs to. |
[zone_id].loc_name |
String | The location name. |
[zone_id].total_visits |
Integer | Total zone entries for the full requested period. |
[zone_id].total_passing_by |
Integer | Total passing-by events for the full requested period. |
[zone_id].drop_in_rate |
Float | Drop-in rate as a percentage for the full requested period. |
[zone_id].details |
Array | Time-series breakdown for this zone at the requested interval. Same structure as details.current but scoped to a single zone. |
zone_details.comparison |
Object | Empty unless comparison dates were set. When populated, has the same structure as zone_details.current. |
Error reference
All three data endpoints use standard HTTP status codes. When an error occurs, no additional JSON error body is returned.
| HTTP status | Meaning | Common cause |
|---|---|---|
200 OK |
Request succeeded | Includes cases where no data matches the filter combination. Check the response array or insights array length before assuming data is missing. |
400 Bad Request |
The request was malformed | Missing required parameters (start_date or end_date), invalid date format, unsupported aggregate_by value for the date range, or max_dwell exceeding 10800. |
401 Unauthorized |
Authentication failed | Missing or malformed Authorization header, or invalid token. See Authentication. |
403 Forbidden |
The token does not have access to the requested resource | The location or organisation is outside the token's scope. |
500 Internal Server Error |
An unexpected error occurred on the Indivd side | Check indivd.statuspage.io for active incidents before investigating your own configuration. |
Comments
0 comments
Please sign in to leave a comment.