Traffic & installs

Four BigQuery/GA4-backed endpoints sit alongside the partner Metrics: classified traffic sources as a period series, traffic by keyword, keyword performance (scraped rank plus a BigQuery install overlay), and attributed installs grouped by source, keyword, or category. Every endpoint returns the shared object: "list" envelope — paginated, with coverage and metadata — and a default trailing 90-day window when you pass no dates.


Common parameters

Every endpoint takes the app ULID in the path and the same date / pagination query parameters. The per-endpoint sections only call out the extra parameters specific to that endpoint (granularity, group_by, filter[keyword], sort).

Path parameter

  • Name
    app
    Type
    string
    Description

    The team app's ULID, e.g. 01JN4HKQX0000000000000000.

Query parameters

  • Name
    start_date
    Type
    string
    Description

    YYYY-MM-DD. Start of the window. Defaults to 90 days ago when omitted.

  • Name
    end_date
    Type
    string
    Description

    YYYY-MM-DD. Must be greater than or equal to start_date. Defaults to today when omitted.

  • Name
    page
    Type
    integer
    Description

    The page to return. Default 1.

  • Name
    per_page
    Type
    integer
    Description

    Rows per page. Default 50, maximum 200.

Request

GET
/api/v1/apps/:app/traffic/sources
curl https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/traffic/sources \
  -H "Authorization: Bearer rk_live_..."

Traffic

Traffic sources

Classified traffic to the app's listing, broken into fixed-length periods. Each point carries the period's start_date/end_date, the period totals (sessions, page_views, installs), and a sources array — the per-source breakdown with each source's sessions, installs, and percentage (its share of the period's installs, 57.9 = 57.9%).

Additional parameters

  • Name
    granularity
    Type
    string
    Description

    Period length: week (7-day, default) or biweekly (14-day). BigQuery traffic is aggregated into fixed-length periods, so unlike the metric series there is no day or month.

Request

GET
/api/v1/apps/:app/traffic/sources
curl -G https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/traffic/sources \
  -H "Authorization: Bearer rk_live_..." \
  -d start_date=2026-05-01 \
  -d end_date=2026-05-31 \
  -d granularity=week

Response

{
  "object": "list",
  "url": "/api/v1/apps/01JN4HKQX0000000000000000/traffic/sources",
  "page": 1,
  "per_page": 50,
  "total_count": 5,
  "has_more": false,
  "coverage": {
    "requested": { "start": "2026-05-01", "end": "2026-05-31" },
    "available": { "start": "2026-05-01", "end": "2026-05-28" }
  },
  "metadata": { "bigquery_sync_status": "complete", "granularity": "week" },
  "data": [
    {
      "start_date": "2026-05-01",
      "end_date": "2026-05-07",
      "sessions": 1240,
      "page_views": 1985,
      "installs": 38,
      "sources": [
        {
          "source": "Shopify App Store search",
          "sessions": 720,
          "installs": 22,
          "percentage": 57.9
        }
      ]
    }
  ]
}

Traffic by keyword

Per-keyword traffic from the BigQuery search-ranking data: each row splits installs and pageviews into organic vs ad and reports the average organic / ad rank, the total_installs, and the organic / ad share of those installs (79.1 = 79.1%). avg_organic_rank / avg_ad_rank are null when the keyword never ranked that way.

Additional parameters

  • Name
    filter[keyword]
    Type
    string
    Description

    Case-insensitive substring match on the keyword (max 100 chars).

  • Name
    sort
    Type
    string
    Description

    Column to sort by, always descending: total_installs (default), organic_installs, or ad_installs.

Request

GET
/api/v1/apps/:app/traffic/keywords
curl -G https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/traffic/keywords \
  -H "Authorization: Bearer rk_live_..." \
  -d "filter[keyword]=email" \
  -d sort=organic_installs

Response

{
  "object": "list",
  "url": "/api/v1/apps/01JN4HKQX0000000000000000/traffic/keywords",
  "page": 1,
  "per_page": 50,
  "total_count": 18,
  "has_more": false,
  "coverage": {
    "requested": { "start": "2026-03-01", "end": "2026-05-31" },
    "available": { "start": "2026-03-01", "end": "2026-05-31" }
  },
  "metadata": { "bigquery_sync_status": "complete" },
  "data": [
    {
      "keyword": "email marketing",
      "organic_installs": 34,
      "organic_pageviews": 512,
      "avg_organic_rank": 4.2,
      "ad_installs": 9,
      "ad_pageviews": 140,
      "avg_ad_rank": 2.0,
      "total_installs": 43,
      "organic_share": 79.1,
      "ad_share": 20.9
    }
  ]
}

Keywords

Keyword performance

The app's organic + sponsored App Store ranking for every keyword it ranks for — scraped daily and always available — with a BigQuery install/view overlay layered on top. The scraped half (organic_rank/organic_page/organic_change, sponsored_rank/sponsored_page/sponsored_change) is null where the app does not rank that way; positive *_change means the rank improved. The overlay (views, installs, organic_installs, ad_installs) is scoped to the date window and zero-filled when BigQuery is not connected.

Because the scraped surface stands on its own, this endpoint never returns 409 — it degrades gracefully to a zero overlay. The date window only scopes the BigQuery overlay.

Additional parameters

  • Name
    sort
    Type
    string
    Description

    Sort column: rank (best organic rank ascending, default), installs (BigQuery installs descending), or keyword (alphabetical).

Request

GET
/api/v1/apps/:app/keywords
curl -G https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/keywords \
  -H "Authorization: Bearer rk_live_..." \
  -d sort=installs

Response

{
  "object": "list",
  "url": "/api/v1/apps/01JN4HKQX0000000000000000/keywords",
  "page": 1,
  "per_page": 50,
  "total_count": 64,
  "has_more": true,
  "coverage": {
    "requested": { "start": "2026-03-01", "end": "2026-05-31" },
    "available": { "start": "2026-03-01", "end": "2026-05-31" }
  },
  "metadata": { "bigquery_sync_status": "complete", "installs_available": true },
  "data": [
    {
      "keyword": "inventory sync",
      "organic_rank": 4,
      "organic_page": 1,
      "organic_change": 2,
      "sponsored_rank": 1,
      "sponsored_page": 1,
      "sponsored_change": -1,
      "views": 320,
      "installs": 18,
      "organic_installs": 12,
      "ad_installs": 6
    }
  ]
}

Installs

Attributed installs

BigQuery-attributed installs over the window — distinct from /metrics/installs, which is the Partner-reported count. The group_by dimension selects the bucket shape, and each row carries only the keys for its dimension:

  • source (default) — source, installs, share (percentage of total attributed installs).
  • keywordkeyword, views, started_installs ("Add app" clicks), completed_installs, conversion_rate (completed ÷ views, %), plus organic/ad install + pageview splits (null when no ranking row exists for the keyword).
  • categorycategory, views, started_installs, completed_installs, completion_rate (completed ÷ started, %; null when no started installs).

The dimension is echoed in metadata.group_by.

Additional parameters

  • Name
    group_by
    Type
    string
    Description

    Attribution dimension: source (default), keyword, or category.

Request

GET
/api/v1/apps/:app/installs
curl https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/installs \
  -H "Authorization: Bearer rk_live_..."

group_by=source

{
  "object": "list",
  "url": "/api/v1/apps/01JN4HKQX0000000000000000/installs",
  "page": 1,
  "per_page": 50,
  "total_count": 2,
  "has_more": false,
  "coverage": {
    "requested": { "start": "2026-03-01", "end": "2026-05-31" },
    "available": { "start": "2026-03-01", "end": "2026-05-31" }
  },
  "metadata": { "bigquery_sync_status": "complete", "group_by": "source" },
  "data": [
    { "source": "organic", "installs": 142, "share": 68.5 },
    { "source": "ad", "installs": 65, "share": 31.5 }
  ]
}

group_by=keyword

{
  "object": "list",
  "url": "/api/v1/apps/01JN4HKQX0000000000000000/installs",
  "page": 1,
  "per_page": 50,
  "total_count": 12,
  "has_more": false,
  "coverage": {
    "requested": { "start": "2026-05-01", "end": "2026-05-31" },
    "available": { "start": "2026-05-01", "end": "2026-05-31" }
  },
  "metadata": { "bigquery_sync_status": "complete", "group_by": "keyword" },
  "data": [
    {
      "keyword": "inventory sync",
      "views": 320,
      "started_installs": 40,
      "completed_installs": 18,
      "conversion_rate": 5.63,
      "organic_installs": 12,
      "ad_installs": 6,
      "organic_pageviews": 280,
      "ad_pageviews": 40
    }
  ]
}

Response shapes

All four endpoints share the object: "list" envelope; only the data row shape differs.

List envelope (object: "list")

  • Name
    object
    Type
    string
    Description

    Always "list".

  • Name
    url
    Type
    string
    Description

    The endpoint path for this request.

  • Name
    page
    Type
    integer
    Description

    The current page number (1-based).

  • Name
    per_page
    Type
    integer
    Description

    Rows per page.

  • Name
    total_count
    Type
    integer
    Description

    Total rows across every page.

  • Name
    has_more
    Type
    boolean
    Description

    Whether further pages exist.

  • Name
    coverage
    Type
    object
    Description

    What was requested vs what was available. available is null when no data fell in range.

  • Name
    metadata
    Type
    object
    Description

    bigquery_sync_status plus per-endpoint keys — e.g. granularity (sources), group_by (installs), installs_available (keywords).

  • Name
    data
    Type
    array
    Description

    The rows; shape depends on the endpoint (see below).

Traffic-source point

  • Name
    start_date
    Type
    string
    Description

    Inclusive period start (YYYY-MM-DD), or null when there are no periods.

  • Name
    end_date
    Type
    string
    Description

    Inclusive period end (YYYY-MM-DD), or null when there are no periods.

  • Name
    sessions
    Type
    integer
    Description

    Total listing sessions in the period, across all sources.

  • Name
    page_views
    Type
    integer
    Description

    Total listing page views in the period, across all sources.

  • Name
    installs
    Type
    integer
    Description

    Total installs attributed in the period, across all sources.

  • Name
    sources
    Type
    array
    Description

    Per-source breakdown — each entry has source, sessions, installs, and percentage (share of the period's installs).

Traffic-keyword row

  • Name
    keyword
    Type
    string
    Description

    The search keyword.

  • Name
    organic_installs
    Type
    integer
    Description

    Installs from organic (non-sponsored) appearances.

  • Name
    organic_pageviews
    Type
    integer
    Description

    Page views from organic appearances.

  • Name
    avg_organic_rank
    Type
    number
    Description

    Average organic rank (1 = top), or null when never ranked organically.

  • Name
    ad_installs
    Type
    integer
    Description

    Installs from sponsored (ad) appearances.

  • Name
    ad_pageviews
    Type
    integer
    Description

    Page views from sponsored appearances.

  • Name
    avg_ad_rank
    Type
    number
    Description

    Average ad rank (1 = top), or null when never shown as an ad.

  • Name
    total_installs
    Type
    integer
    Description

    Total installs (organic + ad).

  • Name
    organic_share
    Type
    number
    Description

    Organic share of installs, as a percentage.

  • Name
    ad_share
    Type
    number
    Description

    Ad share of installs, as a percentage.

Keyword-performance row

  • Name
    keyword
    Type
    string
    Description

    The search keyword, or null when the scraped row had no associated keyword.

  • Name
    organic_rank
    Type
    integer
    Description

    Latest scraped organic rank, or null when the app does not rank organically.

  • Name
    organic_page
    Type
    integer
    Description

    Results page the organic rank falls on, or null.

  • Name
    organic_change
    Type
    integer
    Description

    Day-over-day organic rank change (positive = improved), or null.

  • Name
    sponsored_rank
    Type
    integer
    Description

    Latest scraped sponsored (ad) rank, or null when the app has no ad placement.

  • Name
    sponsored_page
    Type
    integer
    Description

    Results page the sponsored rank falls on, or null.

  • Name
    sponsored_change
    Type
    integer
    Description

    Day-over-day sponsored rank change (positive = improved), or null.

  • Name
    views
    Type
    integer
    Description

    Page-view sessions attributed to the keyword in the window (BigQuery overlay); 0 when BigQuery is not connected.

  • Name
    installs
    Type
    integer
    Description

    Completed installs attributed to the keyword in the window (BigQuery overlay); 0 when not connected.

  • Name
    organic_installs
    Type
    integer
    Description

    Organic-sourced installs (BigQuery overlay); 0 when not connected.

  • Name
    ad_installs
    Type
    integer
    Description

    Ad-sourced installs (BigQuery overlay); 0 when not connected.

Install bucket

The bucket carries only the keys for its group_by dimension.

  • Name
    source
    Type
    string
    Description

    group_by=source — attribution source for this bucket. Paired with installs and share (percentage of total attributed installs).

  • Name
    keyword
    Type
    string
    Description

    group_by=keyword — the keyword. Paired with views, started_installs, completed_installs, conversion_rate (completed ÷ views, %), and organic/ad install + pageview splits (null when no ranking row exists).

  • Name
    category
    Type
    string
    Description

    group_by=category — App Store category. Paired with views, started_installs, completed_installs, and completion_rate (completed ÷ started, %; null when no started installs).

Coverage

coverage tells the caller how much data backed the response, so a short or empty result is never ambiguous.

coverage

"coverage": {
  "requested": { "start": "2026-03-01", "end": "2026-05-31" },
  "available": { "start": "2026-03-01", "end": "2026-05-28" }
}

Pagination

Responses are paginated. Use page and per_page (default 50, max 200) to walk the result set, and check has_more / total_count to know when to stop. The metadata on the envelope applies to every page.


Errors

Beyond the universal 401 / 403 / 422 / 429 (see Errors), these endpoints return:

  • 409 — the app's BigQuery / GA4 export isn't usable. error.code is bigquery_integration_not_connected (never connected), bigquery_integration_unauthorized (access revoked or rejected — reconnect in Ranksy), or bigquery_integration_pending (first export still loading — retry shortly). Returned by traffic/sources, traffic/keywords, and installs. This is the BigQuery counterpart to the partner_integration_* 409 on the metric endpoints.
  • No 409 on GET /keywords. It is backed by scraped ranking data, so it always returns rows; the BigQuery install overlay is simply zero-filled when the export is absent.

A bad query parameter (e.g. an unknown group_by, granularity, or sort value, or end_date before start_date) surfaces as 422 validation_failed with error.param naming the offending parameter.


Things to keep in mind

  • BigQuery, not Partner. These four read the GA4/BigQuery export; the metric endpoints read the Shopify Partner integration. The 409 codes are correspondingly different (bigquery_integration_* vs partner_integration_*).
  • Percentages are percentages here. share, percentage, organic_share, ad_share, and the *_rate fields are already in percent (57.9 = 57.9%) — unlike the metric ratios, which are fractions.
  • traffic/sources is a period series. It buckets by week or biweekly only; each point spans start_date..end_date rather than carrying a single date.
  • Attributed ≠ Partner installs. /installs counts BigQuery-attributed installs; /metrics/installs is the Partner-reported count. They will not match.
  • /keywords always answers. Scraped rank/page/change are always present where the app ranks; the install overlay is zero-filled (not 409) when BigQuery is missing — check metadata.installs_available.
  • Default window is 90 days. Omit start_date/end_date for the trailing 90 days; coverage is your source of truth for what actually backed the response.

Was this page helpful?