# Foot Traffic Data API - Visits, Trade Area, Demographics (`nabeelbaghoor/foot-traffic-data-api`) Actor

Get foot traffic data for any US retail location, shopping center or chain: visits and unique visitors, trends by day, week or month, dwell time, visitor loyalty, the true trade area polygon, trade area demographics, where else those visitors shop, rankings against competitors, and retail sales.

- **URL**: https://apify.com/nabeelbaghoor/foot-traffic-data-api.md
- **Developed by:** [Nabeel Hassan](https://apify.com/nabeelbaghoor) (community)
- **Categories:** Real estate, Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.00 / 1,000 place or chain returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Foot Traffic Data API - Visits, Trade Area, Demographics

Measure how many people visit any US retail location, shopping center or chain - and when they come, how long they stay, how often they return, where they travel from, who they are, where else they shop, and how the place ranks against its competitors.

### What this actor does

- **Visits and visitors, with the panel behind them.** Every visit row carries the extrapolated totals for the whole population **and** the panel counts the provider actually observed. A modelled 433,000 visits built on 11,500 observed ones is a different claim from one built on 800, and only one of those two numbers tells you which you are looking at.
- **Traffic over time.** Daily, weekly or monthly trends, and breakdowns by day of the week, by hour of the day and by dwell time band, with the average and median minutes stayed.
- **Loyalty.** Visitors split by how many times they came back, as counts and as percentages, with the average and median visits per visitor.
- **The real trade area.** The GeoJSON polygon of where the visitors actually travelled from, drawn to enclose a chosen share of the traffic, plus a drive-time variant and the list of census block groups that sent them.
- **Trade area demographics.** Who lives in that polygon: census demographics and, where your plan covers them, population statistics, consumer landscape, market outlook, spending patterns, workplace and persona segments. Benchmarked nationwide or against the state, for the potential population or only the block groups that actually visited.
- **Visitor journey.** The other chains and the other places those same visitors frequent, with the share of visitors each accounts for and the distance from the subject.
- **Rankings.** Where a venue sits nationwide, in its state, its DMA, its CBSA and within a radius - against its own chain, its category or its whole business domain, on raw visits or on visits per square foot - plus the venues ranked immediately around it.
- **Retail sales.** Spend, transaction counts and average ticket size, as an overview or over time.
- **Pay per result.** You are charged for rows carrying a real record. Entities with no data over the window, reports the provider withholds, and searches that match nothing are all free.

### Bring your own key

This actor calls the provider with **your own API key**. Paste it into the API key field, or set it as the `DATA_API_KEY` secret. Nothing runs on anyone else's credentials, and a run without a key ends cleanly with an explanation rather than failing.

API access needs a paying account with the API add-on enabled; your customer success manager issues the key and sets which entities and data sets your account may read.

### Start with entity search

Every report takes the provider's own identifier, spelled `venue:4ea4f76f1f766e7bbdeccd61` - the `apiId` column, not the bare `entityId`. Run **entity search** first with a name, a point and radius, or a category. Two columns there are worth reading before you spend anything on reports: `isFlagged`, because the provider will not produce reports for a flagged entity, and `isPermitted`, because a search can legitimately return venues your account is not cleared to report on.

### Read the panel column

The provider observes a sample and models the rest. `panelVisits` is the observation and `visits` is the model. They are both on every row for a reason: a thin panel makes a precise-looking total much less precise than it appears.

One case needs care. When you set a **home or work distance filter**, the provider applies it to the extrapolated visits and, in its own words, leaves the panel count showing the full unfiltered panel. The two then describe different populations and their ratio means nothing. Every row from such a run carries `panelIsUnfiltered` set to true, and the run logs a warning, so the trap is visible rather than waiting in a spreadsheet.

### What this actor will not do

The provider's API can also create, rename and delete custom points of interest and tags on your account. Those endpoints are deliberately not implemented here. This actor only reads. An actor should not be able to delete somebody's saved locations, so it cannot.

### Example output

```json
{
  "recordType": "visitMetrics",
  "requested": "venue:4ea4f76f1f766e7bbdeccd61",
  "apiId": "venue:4ea4f76f1f766e7bbdeccd61",
  "found": true,
  "name": "Chuck E. Cheese's",
  "entityType": "venue",
  "category": "Attractions",
  "startDate": "2026-01-01",
  "endDate": "2026-06-30",
  "visits": 433202,
  "visitors": 184092,
  "panelVisits": 11546,
  "panelVisitors": 5655,
  "panelIsUnfiltered": false,
  "visitDurationSegmentation": "10MinOrLonger"
}
```

### FAQ

#### What is foot traffic data and where does it come from?

Foot traffic data counts visits to a physical place. This provider observes a panel of mobile devices, identifies which of them visited a location and for how long, and extrapolates from that sample to an estimate for the whole population. That is why every row here carries both figures: `panelVisits` is what was seen and `visits` is what was modelled from it.

#### What is the difference between visits and visitors?

A visit is one trip to the place. A visitor is one person, however many trips they made. A venue with 433,000 visits from 184,000 visitors is seeing each person come back about 2.4 times over the window - which is the number the loyalty mode breaks down properly, band by band.

#### How do I get the trade area for a store?

Run **trade area** mode with the entity ID and a date range. It returns the GeoJSON MultiPolygon of where the visitors actually came from, drawn to enclose the share of traffic you set - 70 percent is the usual default. Use **trade area by drive time** for a travel-time ring instead, and **visits by block group** when you want the trade area as a list of neighbourhoods rather than as a shape.

#### What is the difference between a true trade area and a mile ring?

A mile ring is a circle drawn on a map. A true trade area is built from the census block groups the visitors actually came from, so it follows roads, rivers and rival stores rather than geometry. The demographics mode accepts all three methods - true trade area, drive time and mile ring - and each needs its own sizing input, which this actor sends without the others because the endpoint rejects the wrong combination rather than ignoring it.

#### Can I profile the people in a trade area?

Yes, with **trade area demographics**. Choose `potential` to profile everyone living in the trade area, or `captured` to profile only the block groups that actually sent visitors - a smaller and usually more flattering number. Access is per data set: census is standard, and the consumer landscape, spending pattern, workplace and persona sets depend on your plan. A data set your plan does not include is refused with a clear message rather than returned empty.

#### How do I compare a location against its competitors?

**Ranking overview** returns where the venue sits nationwide, in its state, its DMA, its CBSA and within a radius you choose, against its own chain, its category or its whole business domain. **Top ranked** lists the strongest venues in that scope and **closely ranked** lists the ones immediately above and below. Rank on `visitsPerSqft` rather than `visits` when you are comparing places of different sizes.

#### Why does a ranking row say found false with a note?

Because the provider can refuse a ranking for one entity inside an otherwise successful response, by writing a reason where the rank should be - usually because the venue is flagged or unverified. This actor reads that per entity and reports the reason rather than recording a silent null rank, and rows like that are never charged.

#### Why did my report come back as still being built?

Reports are cached rather than computed on demand. The first request for a cold report returns an in-progress status and the provider's documented path is to ask again until it is warm. This actor does that automatically, waiting between attempts. The provider states that in-progress responses do not count against your weekly quota, so the retries are free; only the eventual answer is counted.

#### What are the rate limits?

The general ceiling is ten calls a second with up to five concurrent processes. On top of that there are per-family quotas: report preparation, point of interest queries and ranking reports each have their own hourly and per-minute allowances, and there is a weekly cap on how many distinct entities you may query, which renews on Sunday. This actor paces itself, honours the wait on a rate limit response, and reports the weekly cap as its own kind of problem because waiting will not clear it.

#### Can I report on many places at once?

Visit metrics, visit trends and block groups accept up to 100 entities per request, and this actor batches your list into hundreds automatically. Every other report reads one entity at a time. Note that switching on the nearby activity radius collapses a bulk request to its first entity only, which is why this actor never combines the two.

#### What does it cost?

Pricing is per result. You pay for rows that carry a real record: a place, a visit summary, a trend or breakdown bin, a trade area, a demographic attribute, a journey destination, a ranking, a sales metric or a block group. Entities with no data over the window, reports the provider withholds for privacy or for a flagged entity, and searches that match nothing are all free. Apify platform usage is included in the per-result price.

#### Does the actor fail if my key is wrong?

No. A missing key, a refused key, an exhausted weekly quota and an input that needs filling in all end the run cleanly with the reason as the run's status message. Only a real fault - a provider outage, or a bug here - fails a run.

### Keyword map

foot traffic data API, foot traffic counts by location, retail location intelligence API, visits and visitors data, trade area analysis API, true trade area polygon, trade area demographics, drive time trade area, dwell time data, visitor loyalty data, customer journey data, cross shopping data, retail benchmarking API, visits per square foot, shopping center foot traffic, chain performance data, site selection data, census block group visits, retail sales data by location, POI visit data.

# Actor input Schema

## `mode` (type: `string`):

Entity search finds the provider's identifier for a place, a shopping centre or a chain, and every other mode starts there. The visit modes count and break down traffic. Trade area draws where the visitors came from and demographics profiles who lives there. Visitor journey lists where else those visitors go. Ranking places the venue against its category, chain or neighbours. Retail sales reads spend.

## `apiIds` (type: `array`):

One entity ID per line in the provider's own spelling, for example venue:4ea4f76f1f766e7bbdeccd61. This is the apiId column from entity search, not the bare entityId. Visit metrics, visit trends and block groups take up to 100 per request; every other report reads them one at a time.

## `entityName` (type: `string`):

Entity search: text that appears in the place's name, for example Walmart or Chuck E Cheese.

## `latitude` (type: `string`):

Entity search: decimal latitude of the point to search around. Must be paired with a longitude.

## `longitude` (type: `string`):

Entity search: decimal longitude of the point to search around. A point search returns venues and complexes but never chains.

## `radiusMiles` (type: `integer`):

Entity search: how far around the point to look, from 0.01 to 2000 miles. The provider's own default is 0.01 miles, which is about fifty feet and finds almost nothing, so this actor uses 1 mile when you leave it blank.

## `groupCategory` (type: `string`):

Entity search: the business domain, for example Dining, Apparel or Grocery.

## `category` (type: `string`):

Entity search: the category within a group, for example Fast Food & QSR.

## `subCategory` (type: `string`):

Entity search: the narrowest classification, for example Pizza Place.

## `entityTypes` (type: `array`):

Entity search: which kinds of entity to return. Leave empty for all three. A venue is one location, a complex is a mall or centre, and a chain is every location of a brand.

## `includeFlaggedEntities` (type: `boolean`):

Entity search: also return entities the provider has flagged. Flagged entities are returned with a flag column but the provider will not produce reports for them, so this is useful for auditing rather than for building a report list.

## `startDate` (type: `string`):

First day of the window to report on, written as YYYY-MM-DD. Required by every report mode.

## `endDate` (type: `string`):

Last day of the window to report on, written as YYYY-MM-DD.

## `granularity` (type: `string`):

Visit trends and block groups: the size of each bin. A daily trend over a long window is the slowest report on this API.

## `visitDurationSegmentation` (type: `string`):

Which visits to count. The provider's default picks a segment per venue that reflects how people normally use it, and a chain whose venues use different defaults reports back as mixed.

## `audienceTypes` (type: `array`):

Count only these kinds of people. Leave empty to count everyone. Employees and residents are usually excluded from a retail traffic read, because a member of staff visits every working day.

## `dwellTimeFilter` (type: `string`):

Count only visits of a certain length, written as ">=10" or "<150" in minutes. The provider accepts only those two operators, so ">" is read as ">=" and "<=" as "<" rather than being rejected.

## `daysOfWeek` (type: `array`):

Count only visits on these days. Monday is 1 and Sunday is 7, so a weekend read is 6 and 7.

## `fromHour` (type: `string`):

Count only visits from this hour onwards, written as "08:00 am". The provider needs both ends of the range, so a from hour without a to hour is dropped rather than sent.

## `toHour` (type: `string`):

Count only visits up to this hour, written as "11:59 pm".

## `distanceFilter` (type: `string`):

Count only visits from within a distance in miles, written as "10-250", ">=10" or "<=100". Note that the provider applies this to the extrapolated visits and NOT to the panel counts, so on a filtered run the two stop being comparable and every row is flagged accordingly.

## `distanceFrom` (type: `string`):

Whether the distance filter measures from the visitor's home or their work.

## `nearbyRadiusFeet` (type: `string`):

Switch the report to nearby activity, measuring traffic passing within this many feet rather than visits to the place itself. Note that setting this collapses a bulk request to its first entity only, so it is left off bulk modes.

## `tradeAreaMethod` (type: `string`):

Demographics only: how the trade area is drawn. True trade area uses the block groups the visitors actually came from, drive time uses a travel time ring, and mile ring uses a plain radius. Each needs its own sizing input and ignores the other two.

## `trafficVolumePercent` (type: `integer`):

What share of the visits the trade area polygon must enclose. Setting 70 draws a shape covering at least 70 percent of the traffic. The two endpoints accept different ranges, 30 to 100 for the trade area and 1 to 99 for demographics, so the value is held inside whichever applies.

## `allocationType` (type: `string`):

How a census block group is judged to be inside the trade area. Weighted centroid moves the centroid towards where the block group's population actually lives, which is the better default in a block group with a lake or a park in it.

## `withinDistanceMiles` (type: `integer`):

Exclude visitors living further than this from the place, in miles. Keeps a tourist destination's trade area from stretching across the country.

## `driveTimeMinutes` (type: `integer`):

Drive time trade area: the travel time ring to draw, from 5 to 200 minutes.

## `ringRadiusMiles` (type: `integer`):

Demographics with the mile ring method: the plain radius to profile, from 0.2 to 250 miles.

## `benchmarkScope` (type: `string`):

Whether the demographic profile is indexed against the whole country or against the state.

## `demographicsAudience` (type: `string`):

Potential profiles everyone living in the trade area. Captured profiles only the block groups that actually sent visitors, which is a smaller and more flattering number.

## `demographicsDataset` (type: `string`):

Which third-party data set to profile with. Access is per data set, and a set your plan does not include is refused rather than returned empty.

## `journeyCategories` (type: `array`):

Visitor journey: restrict the other places those visitors go to these categories, one per line. Leave empty for every category.

## `minimalVisitFrequency` (type: `integer`):

Visitor journey: how often a visitor must have gone to the other place for it to count, from 0 to 99.

## `journeyLimit` (type: `integer`):

Visitor journey: how many destinations to return, up to 50.

## `rankingPeriod` (type: `string`):

A named window for a ranking. The provider refuses a request carrying both a named period and explicit dates, so setting this drops the start and end dates rather than sending both.

## `rankingScope` (type: `string`):

What the place is ranked against: the other locations of its own chain, the other places in its category, or the whole business domain.

## `rankingMetric` (type: `string`):

Rank on raw visits, or on visits per square foot, which is the fairer comparison between a big box and a kiosk.

## `rankingRegion` (type: `string`):

Top ranked and closely ranked: the geography to rank inside. A number is a radius in miles around the place; the rest are administrative areas.

## `rankingDistanceMiles` (type: `string`):

Ranking overview: the radius in miles used for the local rank, alongside the nationwide, state, DMA and CBSA ranks it always returns.

## `rankingLimit` (type: `integer`):

Top ranked and closely ranked: how many neighbouring venues to return, up to 1000.

## `cbgTrafficVolumePercent` (type: `string`):

Visits by block group: whether to list the block groups covering 70 percent of the traffic or all of it.

## `maxResults` (type: `integer`):

Stop after this many rows. Each row is one charged result, so this is the ceiling on what a run can cost.

## `requestsPerMinute` (type: `integer`):

How fast to call the provider. The published ceiling is ten calls a second with five concurrent processes, and a rate limit response is honoured with the wait the provider publishes.

## `baseUrl` (type: `string`):

Only set this if the provider has given you a different host. Leave blank for the standard one.

## `apiKey` (type: `string`):

Your own location intelligence API key. API access needs a paying account with the API add-on enabled; your customer success manager issues the key. Leave blank to use the DATA\_API\_KEY environment secret instead.

## Actor input object example

```json
{
  "mode": "entitySearch",
  "includeFlaggedEntities": false,
  "granularity": "month",
  "visitDurationSegmentation": "",
  "distanceFrom": "home",
  "nearbyRadiusFeet": "",
  "tradeAreaMethod": "tta",
  "allocationType": "weightedCentroid",
  "benchmarkScope": "nationwide",
  "demographicsAudience": "potential",
  "demographicsDataset": "census",
  "rankingPeriod": "",
  "rankingScope": "category",
  "rankingMetric": "visits",
  "rankingRegion": "15",
  "rankingDistanceMiles": "",
  "cbgTrafficVolumePercent": "",
  "maxResults": 100,
  "requestsPerMinute": 120
}
```

# Actor output Schema

## `records` (type: `string`):

One row per record, alongside the entity that produced it.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("nabeelbaghoor/foot-traffic-data-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("nabeelbaghoor/foot-traffic-data-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call nabeelbaghoor/foot-traffic-data-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nabeelbaghoor/foot-traffic-data-api"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/yPDprPPdn73Lf1lqw/builds/6hKF3d7lao5phNb11/openapi.json
