close
Skip to content
Docs

Query Web Analytics with the API

Use the Web Analytics API to query page views, visitors, and custom events from your Vercel projects. The API uses the same aggregated data model as the dashboard, so you can build reports, embed metrics, or combine Web Analytics with your own business data.

Before querying Web Analytics from the API:

  • Enable Web Analytics for the project you want to query.
  • Create a Vercel access token. See REST API authentication.
  • Find the projectId for the project.
  • For team projects, find the team's teamId or slug and include one in each request. For projects owned by your personal account, omit teamId and slug.

The examples on this page use $VERCEL_TOKEN, prj_1234567890, and team_1234567890 as placeholder values. Replace them with your access token, project ID, and team ID. If you prefer a team slug, replace teamId=team_1234567890 with slug=your_team_slug_here.

For complete endpoint parameters and response fields, see the Web Analytics REST API reference.

Web Analytics API queries start with a dataset. Choose the dataset that matches the type of activity you want to analyze:

DatasetWhat it representsMetricsUse for
VisitsAutomatically tracked page viewspageviews and visitorsTraffic reports, content performance, referrer analysis, and route popularity
EventsCustom events sent with track()count and visitorsFunnels, conversion events, feature adoption, and custom interaction reports

Each dataset supports two query styles:

Query styleEndpointsUse when
Countvisits/count, events/countYou need one total, such as the lifetime page views for a blog post or total signups for an event. Count endpoints query production data.
Aggregatevisits/aggregate, events/aggregateYou need rows grouped by time or dimension, such as daily page views, top countries, or signups by plan. Aggregate endpoints query data within your plan's reporting window.

Dimensions describe the properties you can group or filter by. Common visit dimensions include requestPath, route, country, referrerHostname, deviceType, browserName, and UTM parameters.

Use requestPath when you want the exact URL path without query parameters, such as /blog/my-post. Use route when you want the framework route pattern, such as /blog/[slug], so traffic from many matching URLs rolls up into one row.

Use by to group results and filter to narrow the dataset before the query runs. Filters use OData syntax, so quote string values and URL-encode the full expression in your request. For example:

requestPath eq '/pricing' and country eq 'US'

In a curl --get request, pass the same expression with --data-urlencode:

--data-urlencode "filter=requestPath eq '/pricing' and country eq 'US'"

You can also query structured dimensions:

  • Use flags/<name> to group or filter events annotated with a feature flag value.
  • Use eventData/<property> to group or filter custom events by data sent with track().

If a flag name or event data property contains characters other than letters, digits, and underscores, wrap it in single quotes. For example, use flags/'beta-banner' or eventData/'signup-source'.

When a grouped query has more distinct values than the requested limit, Web Analytics groups the remaining values into Others. This keeps top-value reports bounded while still preserving the total count represented by the query.

Most Web Analytics API queries follow the same pattern: choose the dataset, choose a count or aggregate endpoint, then combine a filter with one or two grouping dimensions.

QuestionQuery model
How many visitors saw a specific page?Use visits/count with a requestPath filter.
Which routes drove the most page views this week?Use visits/aggregate grouped by route for the selected date range.
How did traffic to a launch page change each day?Use visits/aggregate grouped by day and filtered by requestPath.
Which countries sent visitors to a page?Use visits/aggregate grouped by country and filtered by requestPath.
Which plan generated the most signups?Use events/aggregate filtered by eventName and grouped by eventData/plan.
Which flag variant received the most traffic?Use visits/aggregate or events/aggregate grouped by flags/<name>.

Use a count query when you need one total for a page, such as a public view counter or an internal content scorecard.

cURL
curl --get "https://api.vercel.com/v1/query/web-analytics/visits/count" \
  -H "Authorization: Bearer $VERCEL_TOKEN" \
  --data-urlencode "teamId=team_1234567890" \
  --data-urlencode "projectId=prj_1234567890" \
  --data-urlencode "filter=requestPath eq '/blog/my-post'"

The response contains the total pageviews and visitors that match the filter.

Response
{
  "version": 1,
  "query": {
    "filter": "requestPath eq '/blog/my-post'"
  },
  "data": {
    "pageviews": 1250,
    "visitors": 980
  }
}

Use an aggregate query with a time dimension when you need a chart or report over time. This example queries daily traffic for one page.

cURL
curl --get "https://api.vercel.com/v1/query/web-analytics/visits/aggregate" \
  -H "Authorization: Bearer $VERCEL_TOKEN" \
  --data-urlencode "teamId=team_1234567890" \
  --data-urlencode "projectId=prj_1234567890" \
  --data-urlencode "since=2024-10-01" \
  --data-urlencode "until=2024-10-07" \
  --data-urlencode "by=day" \
  --data-urlencode "filter=requestPath eq '/blog/my-post'"

Each returned row represents one day in the requested range.

Response
{
  "version": 1,
  "query": {
    "since": "2024-10-01",
    "until": "2024-10-07",
    "groupBy": ["day"],
    "filter": "requestPath eq '/blog/my-post'"
  },
  "data": [
    {
      "timestamp": "2024-10-01T00:00:00.000Z",
      "pageviews": 220,
      "visitors": 180
    },
    {
      "timestamp": "2024-10-02T00:00:00.000Z",
      "pageviews": 245,
      "visitors": 201
    }
  ]
}

Use a dimension group when you want the top values inside a filtered segment. This example finds the top countries for visitors to one page.

cURL
curl --get "https://api.vercel.com/v1/query/web-analytics/visits/aggregate" \
  -H "Authorization: Bearer $VERCEL_TOKEN" \
  --data-urlencode "teamId=team_1234567890" \
  --data-urlencode "projectId=prj_1234567890" \
  --data-urlencode "since=2024-10-01" \
  --data-urlencode "until=2024-10-07" \
  --data-urlencode "by=country" \
  --data-urlencode "limit=5" \
  --data-urlencode "filter=requestPath eq '/blog/my-post'"

Use the same pattern with dimensions such as referrerHostname, deviceType, browserName, or utmCampaign.

Response
{
  "version": 1,
  "query": {
    "since": "2024-10-01",
    "until": "2024-10-07",
    "groupBy": ["country"],
    "filter": "requestPath eq '/blog/my-post'",
    "limit": 5
  },
  "data": [
    {
      "country": "US",
      "pageviews": 640,
      "visitors": 510
    },
    {
      "country": "DE",
      "pageviews": 180,
      "visitors": 150
    }
  ]
}

Use custom event queries when you send business events with track(). This example counts signup events by plan.

cURL
curl --get "https://api.vercel.com/v1/query/web-analytics/events/aggregate" \
  -H "Authorization: Bearer $VERCEL_TOKEN" \
  --data-urlencode "teamId=team_1234567890" \
  --data-urlencode "projectId=prj_1234567890" \
  --data-urlencode "since=2024-10-01" \
  --data-urlencode "until=2024-10-07" \
  --data-urlencode "by=eventData/plan" \
  --data-urlencode "filter=eventName eq 'signup' and eventData/source eq 'pricing'"

This pattern works for any custom data property that you send with the event, such as eventData/source, eventData/location, or eventData/product.

Response
{
  "version": 1,
  "query": {
    "since": "2024-10-01",
    "until": "2024-10-07",
    "groupBy": ["eventData/plan"],
    "filter": "eventName eq 'signup' and eventData/source eq 'pricing'"
  },
  "data": [
    {
      "eventData": "pro",
      "count": 42,
      "visitors": 36
    },
    {
      "eventData": "enterprise",
      "count": 12,
      "visitors": 10
    }
  ]
}
Last updated June 26, 2026

Was this helpful?

supported.