Search specific term/phrase surrounded by double quotes. e.g. “deep linking”
Exclude records that contain a specific term prefixed with a minus. e.g. Android -Firebase

Programmatically query pre-aggregated analytics.

Overview

The Query API lets you use your own unique queries to fetch the particular pre-aggregated analytics data that you're interested in.

Benefits

The Branch Query API gives you access to the same pre-aggregated analytics data that is displayed in your Branch Dashboard, without needing to access the Dashboard itself.

An individual query is constructed from three types of parameters:

  • Authentication parameters that control the access to the data.
  • Data selection keys that define which events are eligible to be counted in the results (e.g. filters).
  • Result format specifiers that define which results are included in the HTTP response and how the results are returned (e.g. sorting).

Limits

LimitationDetails
Rate Limits- 5 requests per second
- 20 requests per minute
- 150 requests per hourIf you've hit the rate limit, you'll see an error message which says Limit is exceeded for org.... in the response body.
Max number of rows returned from API50,000
Max retrievable unique values for a single dimension (e.g. campaigns, ad names, etc.)40,000
Max number of days that can be queried at a time7 days

If more records are required, please make multiple requests with smaller time intervals to pull the necessary data in batches.
Export WindowRolling 2 year window.
Specific Dimension CombinationsIf you are pulling from SAN cost, xx_click, or xx_impression data, you cannot use the following dimension combinations:

1. user_data_os together with user_data_geo_country_code2. last_attributed_touch_data_tilde_secondary_publisher together with user_data_geo_country_code

Try It!

Try out the Query API in your browser, using your Branch data:

Post Query

We also strongly suggest checking out our Query Recipe Book for use cases and examples related to this API. It has screenshots of Branch Dashboard visualizations alongside the queries you would need to make to pull the same data from the API. Try it for a quick way to get up and running with this API!

Getting Started

Prerequisites

In order to use the Query API, you first need to:

  1. Create a Branch Dashboard.
  2. Enable Universal Ads and start running ad campaigns from your Branch account.
  3. Implement the appropriate Branch SDK into your mobile app (iOS | Android).
  4. Make sure you have the appropriate permissions set on your user account. See the Access section for more.

Access

General Access

To access the Query API, a user must have both Aggregate Data and Export access enabled on their account.

Agency Access

If you work with an agency that runs your advertising campaigns and want to give them access to export the subsequent data, you can provide them with access to the Export API.

To provide an agency team member with access to the Export API:

  1. In the left-hand navigation, under Setup & Testing, click on Account Settings.
  2. On the Account Settings page, click on the Agencies tab.
  3. Expand the agency in question, find the agency team member you want to give access to, hover on the button in the Actions column, and click Edit.
  4. In the Edit Agency Team Member modal:
    1. Under Access Level, check the Export box.
    2. Under Permissions, check the Aggregate Data box.
  5. Add data filters (optional):
    1. Under Data Filters, toggle any necessary data filters on/blue. Exported data will be filtered accordingly.
  6. Click Save.
1246

🚧

Agency-Tagged Data

If you do not enable the Only Show Agency-Tagged Data data filter, the Agency Team Member will be able to export aggregate data associated with all of your campaigns, regardless if they are associated with them or not.

Authentication

Calls to the Query API require your Branch Key and Branch Secret. Both your Branch Key and your Branch Secret can be obtained through your Branch Dashboard Account Settings.

Usage

Post Query

Request Info

Export Request

POST /v1/query/analytics
Content-Type: application/json
Host: api2.branch.io

Request Headers

HeaderDescriptionRequired
acceptapplication/jsonYes
content-typeapplication/jsonYes

Request Query Parameters

ParameterTypeDescriptionRequired
branch_keyStringThe Branch Key for the relevant application.Yes
branch_secretStringThe Branch Secret for the relevant application, used for authentication.Yes
limitIntegerThe maximum number of results to return in the response.

Default value: 100
Max value: 1000

An example: if the granularity in the request body is set to day, Branch will pull results up to the limit for each day. So if the limit is set to 1000 and 5 days' worth of data is queried, then this API will return up to 5000 results.
No
afterIntegerA pagination parameter that indicates the index of the first result to return in the response.

Default value: 0

An example: In a query with 100 results returned, setting after to 50 would return elements 51-100.
No
query_idStringValue passed for this parameter get returned as a query parameter within the paging object.

Default value: null

This parameter locks the last event to include in a query, so new events that occur between queries are not added to the results. This prevents count change over time.

Note: The query_id parameter should be treated as temporary and should only be used when retrieving pages of an existing query where the pagination URLs already have query_id set as a parameter. Do not attempt to change the query_id between requests or to include a query_id with a different query request.
No

Request Body Parameters

ParameterTypeDescriptionRequired
start_dateDateA timestamp representing the oldest date to return data for. Timezone of the timestamp is set in your Branch Dashboard configuration.

Format is an ISO-8601 compliant date-time string, for example: "2024-01-20"
Yes
end_dateDateA timestamp representing the most recent date to return data for. Timezone of the timestamp is set in your Branch Dashboard configuration.

No events triggered after end_date will be counted in the query results.

The end_date parameter cannot be more than 7 days after the start_date parameter.

Format is an ISO-8601 compliant date-time string, for example: "2024-01-20"
Yes
data_sourceStringThe type of event to query for, prefixed with the source.

For example, the source eo combined with the open event type come together to make eo_open, which pulls Branch app opens.

Valid Branch data source values:
eo_impression
eo_click
xx_impression
xx_click
eo_branch_cta_view
eo_sms_sent
eo_open
eo_install
eo_reinstall
eo_web_session_start
eo_pageview
eo_commerce_event
eo_custom_event
eo_content_event
eo_dismissal
eo_user_lifecycle_event
cost
Yes
aggregationStringHow to count events towards the final result count.

Possible aggregation values:
unique_count
total_count
revenue
cost
cost_in_local_currency

Note: When using unique_count, each event is only counted if an event triggered by that user has not already been seen. For example, if 10 users each trigger 3 opens, only 10 open events will be counted.
Yes
dimensionsArray of StringsList of event fields to use as splits for the query.

Results counts are returned and grouped with other events with matching values for each key provided in dimensions.

See the Dimensions section for a complete list.
Yes
filtersArray of StringsAn object where each key is a valid dimension, and each value is an array of string values to check against.

If a key is prefixed with a !, then any event with that dimension value will be excluded. Otherwise, only events with dimension values matching the filter will be counted.

See the Example Queries section for examples of the filters array.

Also see the Dimensions section for a complete list of valid key values. Any key may be used with the ! prefix.
No
enable_install_recalculationBooleanDe-dupe unattributed installs caused by duplicate events from non-opt-in users coming from paid ads.

This parameter is related to iOS 14.5 privacy changes.
No
granularityStringRange of time to roll multiple events into a single result count.

For example, with a granularity value of day, the counts for each day are returned independently, whereas all would return a single count for the entire time range.

Possible values:
all
day

Default value: all

Note: When you set all for this key, Branch will return the data grouped by start_date. The start_date shown is for the start of the range, and does not mean that data is limited to just that day.
No
ordered_byStringThe result key to sort results by.

Only 1 sort key is supported.

Possible values include any dimensions value or the value of aggregation.

Possible numerical sorting values:

- unique_count
- total_count
- revenuePossible chronological sorting values:

- timestampPossible lexicographical sorting values:

- All othersNote: It is not possible to provide an explicit sort method to the query, so the sort type is chosen automatically based on the value of this ordered_by parameter. Behavior for comparison of equal values is left undefined, and as such, the sort is not considered order stable for identical values.
No
orderedStringThe direction by which to order the results.

Possible values:
ascending
descending

Default values:
descending
No
zero_fillBooleanWhether to return result objects where the result count is 0.

If set to false, empty results will be omitted from the response.

If true, fields for empty results will be loaded with null or 0 to provide a schema.

See the Example Queries section for an example of how this flag works.
No

Response Info

Response Body Parameters

ParameterTypeDescription
resultsList of ObjectsA list of JSON objects that contain result information.
resultObjectA JSON object containing the queried values, for example attributed or total_count.

Nested inside results, alongside timestamp.
timestampDateThe date and time when the data related to the result was created.

Nested inside results, alongside result.
pagingObjectA JSON object that includes the total number of results from the query, called total_count.

This object will also include the number that the results are limited to, if that was included in the request.

See limit and after in the Request Query Parameters section for further information.

Example Request & Response

Total Installs

Below is an example of a basic query that pulls total number of installs per day, split by whether attributed is true or false. The number of results is limited to 5.

curl -X POST -H "Content-Type: application/json" -d '{
  "branch_key":"<YOUR_BRANCH_KEY>",
  "branch_secret":"<YOUR_BRANCH_SECRET>",
  "start_date": "2022-03-01",
  "end_date": "2022-03-07",
  "data_source": "eo_install",
  "dimensions": [
    "attributed"
  ],
  "enable_install_recalculation": true,
  "granularity": "day",
  "aggregation": "total_count"
}' "https://api2.branch.io/v1/query/analytics?limit=5"
{
    "results": [{
        "result": {
            "attributed": "false",
            "total_count": 44
        },
        "timestamp": "2022-03-05T00:00:00.000Z"
    }, {
        "result": {
            "attributed": "false",
            "total_count": 23
        },
        "timestamp": "2022-03-07T00:00:00.000Z"
    }, {
        "result": {
            "attributed": "true",
            "total_count": 14
        },
        "timestamp": "2022-03-05T00:00:00.000Z"
    }, {
        "result": {
            "attributed": "false",
            "total_count": 12
        },
        "timestamp": "2022-03-03T00:00:00.000Z"
    }, {
        "result": {
            "attributed": "false",
            "total_count": 10
        },
        "timestamp": "2022-03-02T00:00:00.000Z"
    }],
    "paging": {
        "next_url": "/v1/query/analytics?limit=5&after=5",
        "total_count": 13
    }
}

See Example Queries for more examples.

Appendix

Dimensions

General Information

DimensionDescription
nameName.
originOrigin of the data.
timestampTimestamp of the data.
deep_linkedIs the data deep linked? Can be true or false.
from_desktopIs the data from desktop? Can be true or false.
attributedIs the data attributed? Can be true or false.

User Information

DimensionDescription
user_data_app_storeUser's app store.

Not applicable to the following data source options:
eo_impression,
eo_click,
xx_impression,
xx_click,
eo_branch_cta_view,
eo_sms_sent,
eo_web_session_start,
eo_pageview,
eo_dismissal,
cost
user_data_app_versionUser's version of the app.
user_data_osUser's operating system.
user_data_languageUser's language.
user_data_platformUser's platform.
"user_data_environment"User's environment.
user_data_geo_dma_codeUser's geographical Designated Market Area code.
user_data_geo_country_codeUser's country code.
user_data_countryUser's country.
user_data_geo_region_enUser's region.
user_data_opted_inIs user opted in?
user_data_opted_in_statusUser's opt-in status.

Custom Event Information

DimensionDescription
event_data_custom_param_1
event_data_custom_param_2
event_data_custom_param_3
Available dimensions for custom event data.

Not applicable to the following data source options:
eo_impression,
eo_click,
xx_impression,
xx_click,
eo_branch_cta_view,
eo_sms_sent,
eo_pageview,
eo_dismissal,
cost

Click & Impression Source Definitions

Data SourceDescription
eo_impressionReal-time user device-level impressions and ad-views triggered via Impression Tracking Ad Links.

SAN ad partner's impressions are not included in this data source.
eo_clickReal-time user device-level Branch Link clicks.

SAN ad partner's clicks are not included in this bucket.
xx_impressionCombined aggregated data source containing both real-time user device-level impressions as well as SAN ad partner impressions passed to Branch from SAN servers.
xx_click"Combined aggregated data source containing both real-time user device-level Branch Link clicks as well as the SAN ad partner's clicks passed to Branch from SAN servers.

SAN Ad Partners List:

  • Facebook
  • Google Ads
  • X (formerly Twitter)
  • Snap
  • Apple Search Ads
  • TikTok

Example Queries

Installs Per Day Per OS

This query pulls installs per day and splits the results by OS of the device the user installed on. It limits the number of results to 5.

curl -X POST -H "Content-Type: application/json" -d '{
  "branch_key":"<YOUR_BRANCH_KEY>",
  "branch_secret":"<YOUR_BRANCH_SECRET>",
  "start_date": "2017-12-12",
  "end_date": "2017-12-18",
  "data_source": "eo_install",
  "dimensions": [
    "user_data_os"
  ],
  "enable_install_recalculation": true,
  "granularity": "day",
  "aggregation": "total_count"
}' "https://api2.branch.io/v1/query/analytics?limit=5"
{
  "results": [
    {
      "result": {
        "user_data_os": "ANDROID",
        "total_count": 144
      },
      "timestamp": "2017-12-18T00:00:00.000Z"
    },
    {
      "result": {
        "user_data_os": "IOS",
        "total_count": 142
      },
      "timestamp": "2017-12-18T00:00:00.000Z"
    },
    {
      "result": {
        "user_data_os": "IOS",
        "total_count": 191
      },
      "timestamp": "2017-12-17T00:00:00.000Z"
    },
    {
      "result": {
        "user_data_os": "ANDROID",
        "total_count": 194
      },
      "timestamp": "2017-12-17T00:00:00.000Z"
    },
    {
      "result": {
        "user_data_os": "ANDROID",
        "total_count": 246
      },
      "timestamp": "2017-12-16T00:00:00.000Z"
    }
  ],
  "paging": {
    "next_url": "/v1/query/analytics?query_id=CqdBOb&limit=5&after=5",
    "total_count": 14
  }
}

Unique Click Counts

Below is a more complex query for pulling unique click counts. These counts are split out by 4 different dimensions.

This query also has a filter, which filters out any clicks where last_attributed_touch_data_plus_current_feature was MOBILE_DEEPVIEWS or DESKTOP_DEEPVIEWS.

A maximum of 5 results will be returned, in descending order of unique_count. Results with days that had 0 clicks will be returned (and not filtered out) because the zero_fill flag is set to true:

curl -X POST -H "Content-Type: application/json" -d '{
  "branch_key":"<YOUR_BRANCH_KEY>",
  "branch_secret":"<YOUR_BRANCH_SECRET>",
  "start_date": "2017-12-12",
  "end_date": "2017-12-18",
  "data_source": "eo_click",
  "dimensions": [
    "last_attributed_touch_data_tilde_feature",
    "last_attributed_touch_data_tilde_channel",
    "last_attributed_touch_data_tilde_campaign",
    "last_attributed_touch_data_plus_current_feature"
  ],
  "filters": {
    "!last_attributed_touch_data_plus_current_feature": [
      "MOBILE_DEEPVIEWS",
      "DESKTOP_DEEPVIEWS"
    ]
  },
  "ordered": "descending",
  "ordered_by": "unique_count",
  "aggregation": "unique_count",
  "zero_fill": true
}' "https://api2.branch.io/v1/query/analytics?limit=5"
{
  "results": [
    {
      "timestamp": "2017-12-12T00:00:00.000Z",
      "result": {
        "last_attributed_touch_data_tilde_channel": "ads",
        "last_attributed_touch_data_tilde_campaign": "Xmas",
        "last_attributed_touch_data_tilde_feature": "paid advertising",
        "last_attributed_touch_data_plus_current_feature": "ADS",
        "unique_count": 750
      }
    },
    {
      "timestamp": "2017-12-12T00:00:00.000Z",
      "result": {
        "last_attributed_touch_data_tilde_channel": "taptica#1",
        "last_attributed_touch_data_tilde_campaign": "taptica#1",
        "last_attributed_touch_data_tilde_feature": "paid advertising",
        "last_attributed_touch_data_plus_current_feature": "ADS",
        "unique_count": 723
      }
    },
    {
      "timestamp": "2017-12-12T00:00:00.000Z",
      "result": {
        "last_attributed_touch_data_tilde_channel": "Journeys",
        "last_attributed_touch_data_tilde_campaign": "Default Banner",
        "last_attributed_touch_data_tilde_feature": "journeys",
        "last_attributed_touch_data_plus_current_feature": "MOBILE_JOURNEYS",
        "unique_count": 553
      }
    },
    {
      "timestamp": "2017-12-12T00:00:00.000Z",
      "result": {
        "last_attributed_touch_data_tilde_channel": "Apple App Store",
        "last_attributed_touch_data_tilde_campaign": null,
        "last_attributed_touch_data_tilde_feature": "paid advertising",
        "last_attributed_touch_data_plus_current_feature": "ADS",
        "unique_count": 432
      }
    },
    {
      "timestamp": "2017-12-12T00:00:00.000Z",
      "result": {
        "last_attributed_touch_data_tilde_channel": null,
        "last_attributed_touch_data_tilde_campaign": null,
        "last_attributed_touch_data_tilde_feature": "marketing",
        "last_attributed_touch_data_plus_current_feature": "QUICK_LINKS",
        "unique_count": 201
      }
    }
  ],
  "paging": {
    "next_url": "/v1/query/analytics?query_id=EDdBOb&limit=5&after=5",
    "total_count": 143
  }
}

Include or Omit Response Objects

When zero_fill is set to true, response objects with a total_count equal to 0 will be returned alongside other results:

{
    "branch_key":"<YOUR BRANCH KEY>",
    "branch_secret":"<YOUR BRANCH SECRET>",
    "start_date": "2022-02-01",
    "end_date": "2022-02-01",
    "data_source": "xx_click",
    "dimensions": [
            "last_attributed_touch_data_tilde_advertising_partner_name",
            "last_attributed_touch_data_tilde_campaign_id"
    ],
    "ordered": "descending",
    "aggregation": "total_count",
    "zero_fill": true 
}
{
    "result": {
        "last_attributed_touch_data_tilde_advertising_partner_name": "Google AdWords",
        "last_attributed_touch_data_tilde_campaign_id": "78726498102",
        "total_count": 1
    },
    "timestamp": "2022-02-01T00:00:00.000+08:00"
},
{
    "result": {
        "last_attributed_touch_data_tilde_advertising_partner_name": "Google AdWords",
        "last_attributed_touch_data_tilde_campaign_id": "87192837612",
        "total_count": 1
    },
    "timestamp": "2022-02-01T00:00:00.000+08:00"
}
{
    "result": {
        "last_attributed_touch_data_tilde_advertising_partner_name": "Google AdWords",
        "last_attributed_touch_data_tilde_campaign_id": "17384628491",
        "total_count": 0
    },
    "timestamp": "2022-02-01T00:00:00.000+08:00"
}

When zero_fill is set to false, response objects with a total_count equal to 0 are omitted:

{
    "branch_key":"<YOUR BRANCH KEY>",
    "branch_secret":"<YOUR BRANCH SECRET>",
    "start_date": "2022-02-01",
    "end_date": "2022-02-01",
    "data_source": "xx_click",
    "dimensions": [
            "last_attributed_touch_data_tilde_advertising_partner_name",
            "last_attributed_touch_data_tilde_campaign_id"
    ],
    "ordered": "descending",
    "aggregation": "total_count",
    "zero_fill": false 
}
{
    "result": {
        "last_attributed_touch_data_tilde_advertising_partner_name": "Google AdWords",
        "last_attributed_touch_data_tilde_campaign_id": "78726498102",
        "total_count": 1
    },
    "timestamp": "2022-02-01T00:00:00.000+08:00"
},
{
    "result": {
        "last_attributed_touch_data_tilde_advertising_partner_name": "Google AdWords",
        "last_attributed_touch_data_tilde_campaign_id": "87192837612",
        "total_count": 1
    },
    "timestamp": "2022-02-01T00:00:00.000+08:00"
}