Every action in client form. The same capabilities are exposed as AI SDK tools (apps_get, metrics_query, …). Types also ship in the package, so your editor shows all of this on hover.
Find apps by name or publisher. Returns one row per unified app. Default returns Apple and Google listings; pass allStores to include other storefronts. To filter apps by estimate values (e.g. apps with >100k downloads last month) use af.explorer.listProducts. For estimates broken down by time, country, or storefront, use af.metrics.query with datasets estimates.sales or estimates.revenue.
Parameters
qrequiredstring— Search query (app name or publisher).allStoresboolean, defaultfalse— Include storefronts beyond Apple and Google: Amazon, Windows, Steam, Roku, LG TV, Samsung TV, and others.countnumber, default10— Number of results to return.pagenumber, default1— Page number.
Examples
// Find every Electronic Arts app.
await af.apps.search({ q: "electronic arts" })
// Page through long results.
await af.apps.search({ q: "electronic arts", count: 25, page: 2 })
// Find Minecraft on every storefront (e.g. Amazon, Steam, Windows, Roku; not common).
await af.apps.search({ q: "minecraft", allStores: true })List the apps your Appfigures account tracks.
Parameters
countnumber, default10— Number of results to return.pagenumber, default1— Page number.qstring— App name to filter by.filterAppsById(number | string)[]— Only include data about specific apps, by product ID or unified app ID. Takes precedence over the otherfilterAppsBy*keys when set. Storefront, source, or type filters are better for app sets that can be described by those criteria.filterAppsByStorefrontstring[]— Narrow the account's tracked apps to those on these storefronts (e.g. apple:ios, google_play).filterAppsBySource("own" | "shared" | "manual")[]— Narrow the account's tracked apps by tracking relationship.filterAppsByType("app" | "bundle" | "inapp" | "subscription")[]— Narrow the account's tracked apps to products of these types.
Examples
// List your apps with private-data access.
await af.apps.tracked({ filterAppsBySource: ["own","shared"] })
// List your tracked fitness apps.
await af.apps.tracked({ q: "fitness" })
// List just your iOS apps.
await af.apps.tracked({ filterAppsByStorefront: ["apple:ios"] })
// Page through long results.
await af.apps.tracked({ filterAppsBySource: ["own","shared"], count: 50, page: 2 })
// List tracked competitors.
await af.apps.tracked({ filterAppsBySource: ["manual"] })
// Find individual IAPs or subscriptions (not common).
await af.apps.tracked({ filterAppsByType: ["inapp","subscription"] })Get an app's record: basic metadata (name, developer, etc) and, if the user tracks it, what data they can access. Pass a product ID for one storefront; unified app ID for all storefronts together.
Note
The app's full store listing (description, screenshots, etc.) is available through af.store.appListing.
Parameters
appIdrequirednumber | string— The app's unified app ID or product ID.allStoresboolean, defaultfalse— For a unified app ID: include member products across all storefronts (Amazon, Steam, Windows, Roku, etc.). When false,member_productsis restricted to storefronts with app-intelligence coverage (iOS + Google Play). Ignored for product IDs.
Examples
// Get Minecraft's unified-app record (iOS + Google Play by default).
await af.apps.get({ appId: "ua_X7iNgb" })
// Get Minecraft's Google Play product record.
await af.apps.get({ appId: 6938219 })Read catalog fields for one app or many. Fields referenced by query or sort come back automatically; pass extraFields for more. Use ["match","product_id",<id>] for a single app, or combine filters for population queries (e.g. iOS apps using Firebase with $1M+ US revenue). The 120+ fields span ranks, ratings, download and revenue estimates, SDKs, demographics, and more; query grammar and field list in docs/catalog_playbook.md.
Note
Current point-in-time values per app. Aggregates across matching apps live in af.explorer.aggregateProducts; changes over time live in af.metrics.query. For simple name/publisher lookup, see af.apps.search, which is faster and doesn't require the query grammar.
Parameters
queryunknown[], default[]— Explorer query in JSON array format to select matching catalog Products. Missing values and[]match every Product across every storefront. The full field list and query syntax are documented indocs/catalog_playbook.md.extraFieldsstring[]— Additional fields to include beyond those yourqueryorsortalready reference. Find field paths (and which you can read) withaf.explorer.describeFields.sortstring— Explorer field name. The full field list is documented indocs/catalog_playbook.md.order"asc" | "desc", default"desc"— Sort direction.countnumber, default10— Number of results to return.pagenumber, default1— Page number.allowUnscopedNestedboolean, defaultfalse— Escape hatch for intentionally broad queries. Bypasses the default block on unscoped nested predicates that usually inflate results.
Examples
// Find iOS apps that have Firebase installed.
await af.explorer.listProducts({ query: ["and",["match","storefronts","apple:ios"],["nested","all_sdks",["and",["match","all_sdks.id","firebase"],["match","all_sdks.active",true]]]] })
// Rank the biggest US iOS games by revenue.
await af.explorer.listProducts({ query: ["and",["match","storefronts","apple:ios"],["match","categories.all",6014]], sort: "custom_meta[country=us].revenue_estimates_sum_30_days", order: "desc", count: 25 })
// Find US iOS apps in the $100k–$1M/month revenue tier.
await af.explorer.listProducts({ query: ["and",["match","storefronts","apple:ios"],["nested","custom_meta",["and",["match","custom_meta.country","us"],["match","custom_meta.revenue_estimates_sum_30_days",["number_range",100000,1000000]]]]] })
// Page through results.
await af.explorer.listProducts({ query: ["and",["match","storefronts","apple:ios"],["match","categories.all",6014]], count: 50, page: 2 })
// Pass `extraFields` for columns the query doesn't already reference. Common for single-app reads.
await af.explorer.listProducts({ query: ["match","product_id",304004187384], extraFields: ["custom_meta[country=zz].revenue_estimates_sum_365_days","all_sdks[id=firebase].active"] })Aggregate across the full catalog of millions of products across Apple, Google Play, Amazon, and other major stores: counts, averages, min/max, and histograms over any set of matching products. Uses the same query grammar as af.explorer.listProducts; returns aggregates, not product records. For market sizing, benchmarking, and segment analysis.
Note
Returns public catalog estimates only. Real numbers on owned apps (downloads, revenue, subscriptions) live in af.metrics.query.
Parameters
queryunknown[], default[]— Explorer query in JSON array format to select matching catalog Products. Missing values and[]match every Product across every storefront. The full field list and query syntax are documented indocs/catalog_playbook.md.fieldsrequiredstring[]— Field+aggregation pairs (e.g.all_rating/stats,storefronts/terms). Aggregations:stats,terms,histogram,date_histogram,cardinality. The full field list is documented indocs/catalog_playbook.md.allowUnscopedNestedboolean, defaultfalse— Escape hatch for intentionally broad queries. Bypasses the default block on unscoped nested predicates that usually inflate results.termsCountnumber, default20— Maximum buckets returned for eachtermsaggregation. Other aggregation types ignore it.dateHistogramInterval"year" | "quarter" | "month" | "week" | "day"— Bucket granularity for eachdate_histogramaggregation. Other aggregation types ignore it.
Examples
// How many monthly downloads does an average iOS app get in Japan?
await af.explorer.aggregateProducts({ fields: ["custom_meta[country=jp].download_estimates_average_30_days/stats"], query: ["and",["match","storefronts","apple:ios"],["match","countries","jp"]] })
// What's the rating, category mix, and developer concentration for US iOS apps in the $100k–$10M/mo net-revenue tier?
await af.explorer.aggregateProducts({ fields: ["all_rating/stats","categories.all/terms","developer_id/cardinality"], query: ["and",["match","storefronts","apple:ios"],["nested","custom_meta",["and",["match","custom_meta.revenue_estimates_sum_30_days",["number_range",100000,10000000]],["match","custom_meta.country","us"]]]] })
// Are new iOS games still launching at the same rate as two years ago?
await af.explorer.aggregateProducts({ fields: ["release_date/date_histogram"], query: ["and",["match","storefronts","apple:ios"],["match","categories.all",6014],["match","release_date",["range","2024-01-01","2025-12-31"]]] })
// What SDKs do apps commonly ship alongside OneSignal?
await af.explorer.aggregateProducts({ fields: ["all_sdks[*].id/terms"], query: ["nested","all_sdks",["and",["match","all_sdks.id","onesignal"],["match","all_sdks.active",true]]] })
// How do iOS app ratings distribute?
await af.explorer.aggregateProducts({ fields: ["all_rating/histogram"], query: ["match","storefronts","apple:ios"] })
// How many apps are on each storefront?
await af.explorer.aggregateProducts({ fields: ["storefronts/terms"] })List the catalog fields and the current user's access level for each. Search by keyword to find fields. Same field set af.explorer.listProducts and af.explorer.aggregateProducts accept.
Note
Each entry has two access axes: read (gates response columns in af.explorer.listProducts) and query (gates query, sort, and aggregate fields). query: 'partial' means restricted-but-non-empty results. For paths containing [] (array-of-objects members), substitute a bracket filter before use: custom_meta[].download_estimates_sum_30_days → custom_meta[country=us].download_estimates_sum_30_days. Pair with docs/catalog_playbook.md for query grammar.
Parameters
countnumber, default50— Number of results to return.pagenumber, default1— Page number.qstring— Filter bypath,title,description,type.
Examples
// Search for revenue-related fields.
await af.explorer.describeFields({ q: "revenue" })
// List every catalog field with the current user's access level.
await af.explorer.describeFields()Query any numeric dataset for one or more apps. Optionally grouped by up to two dimensions, returned as a nested partition tree, not app records. Independently filterable by country, device type, and date range. filterAppsBy* options narrow the app set (by ID, storefront, source, or type); without one, a query covers every app the account tracks.
Note
Current point-in-time values live in af.explorer.listProducts; counts/averages across the catalog live in af.explorer.aggregateProducts. See docs/numeric_metrics.md for dataset naming conventions and pitfalls.
Parameters
datasetrequiredstring— Dataset to query (e.g. sales.combined_downloads). Seeaf.metrics.describeDatasetsfor the full list and which datasets are private data (visible only for apps you own or that were shared).groupBy("date" | "product" | "unifiedApp" | "country" | "storefront" | "network" | "device")[]— Dimensions to group by. Max 2: the first slot becomes the outer entity type, the second the inner series. Each dimension multiplies the result size.granularity"daily" | "weekly" | "monthly" | "quarterly" | "yearly"— Time granularity when grouping by datecountnumber— Row cap. WithgroupBy, top N of the outer entity type by value (earliest N when grouping by date). WithoutgroupBy, single-page preview.countriesstring[]— Filter to one or more ISO country codes (e.g. US, JP, GB)deviceType"watch" | "handheld" | "tablet" | "tv" | "desktop" | "headset"— Device typeallTimeboolean, defaultfalse— Opt in to the entire history. Without this flag (and withoutstart/end), the query defaults to the last 30 days. Mutually exclusive withstartandend.filterAppsById(number | string)[]— Only include data about specific apps, by product ID or unified app ID. Takes precedence over the otherfilterAppsBy*keys when set. Storefront, source, or type filters are better for app sets that can be described by those criteria.filterAppsByStorefrontstring[]— Narrow the account's tracked apps to those on these storefronts (e.g. apple:ios, google_play).filterAppsBySource("own" | "shared" | "manual")[]— Narrow the account's tracked apps by tracking relationship.filterAppsByType("app" | "bundle" | "inapp" | "subscription")[]— Narrow the account's tracked apps to products of these types.startstring— Start date (YYYY-MM-DD)endstring— End date (YYYY-MM-DD, defaults to today)
Examples
// Get total downloads across your apps with private-data access.
await af.metrics.query({ dataset: "sales.combined_downloads", filterAppsBySource: ["own","shared"] })
// Get revenue split by storefront, plus a top-level total.
await af.metrics.query({ dataset: "sales.combined_revenue", filterAppsBySource: ["own","shared"], groupBy: ["storefront"] })
// Rank the top 5 tracked competitors by estimated monthly revenue.
await af.metrics.query({ dataset: "estimates.revenue", filterAppsBySource: ["manual"], groupBy: ["product"], count: 5 })
// Track Candy Crush Saga's daily download estimates.
await af.metrics.query({ dataset: "estimates.sales", filterAppsById: ["ua_V1Q1uX"], groupBy: ["date"], granularity: "daily" })
// Track net monthly recurring revenue per app, month over month.
await af.metrics.query({ dataset: "subscriptions.mrr", filterAppsBySource: ["own","shared"], groupBy: ["product","date"], granularity: "monthly" })
// Get Minecraft's new ratings.
await af.metrics.query({ dataset: "ratings.new_total", filterAppsById: ["ua_X7iNgb"] })
// Track daily ad spend across your apps.
await af.metrics.query({ dataset: "adspend.cost", filterAppsBySource: ["own","shared"], groupBy: ["date"], granularity: "daily" })
// Compare Candy Crush's December 2025 downloads across the US, Japan, and UK.
await af.metrics.query({ dataset: "estimates.sales", filterAppsById: ["ua_V1Q1uX"], countries: ["US","JP","GB"], groupBy: ["country"], start: "2025-12-01", end: "2025-12-31" })
// Track all-time monthly revenue across your apps with private-data access.
await af.metrics.query({ dataset: "sales.combined_revenue", filterAppsBySource: ["own","shared"], groupBy: ["date"], granularity: "monthly", allTime: true })
// Get Minecraft's review volume by country.
await af.metrics.query({ dataset: "reviews.total", filterAppsById: ["ua_X7iNgb"], groupBy: ["country"] })List every numeric dataset af.metrics.query accepts, one row per dataset with its value type and whether it's limited to your own apps.
Note
A dataset with your_apps_only: true returns data only for apps you own or that were shared with you. af.metrics.query returns nothing for one of these on any other app. Feed any dataset straight into af.metrics.query. Each row's supported_group_by and supported_granularities list how that dataset can be broken down, so you can pick a valid grouping before querying. Pair with docs/numeric_metrics.md for dataset naming conventions and pitfalls.
Parameters
countnumber, default50— Number of results to return.pagenumber, default1— Page number.qstring— Filter bydataset,value_type,label,description.
Examples
// Search by keyword (matches name, label, or description).
await af.metrics.describeDatasets({ q: "combined downloads" })
// Look up one dataset by its exact name.
await af.metrics.describeDatasets({ q: "sales.combined_downloads" })
// List every dataset with its value type and whether it's limited to your own apps.
await af.metrics.describeDatasets()Trace rank history for one or more apps across countries, device types, category subtypes, and categories, as time-series positions with day-over-day deltas.
Note
For the inverse (e.g., "what app is at #10 in UK Games?"), see af.store.topCharts. Keyword search positions are in af.keywords.organic. Pass a unified app ID to cover every storefront with app-intelligence coverage, or a numeric product ID for one storefront.
Parameters
appIdsrequired(number | string)[]— App identifiers (unified app IDs or product IDs)countriesstring[]— Country codes to query. Defaults to every country with rank coverage.granularity"daily" | "hourly", default"hourly"— Sampling rate. Hourly gives the freshest data; passgranularity: "daily"for compact multi-day history.deviceTypes("watch" | "handheld" | "tablet" | "tv" | "desktop" | "headset")[], default["handheld"]— Which device types to include; each ranks in its own chart. Add more to widen the response.subtypes("free" | "paid" | "topgrossing")[], default["free"]— Which category subtypes to include; each ranks in its own chart. Add more to widen the response.categoryIdsnumber[]— Filter response rows to specific category IDs; omit for all. Category IDs come fromaf.store.categories.startstring— Start date (YYYY-MM-DD)endstring— End date (YYYY-MM-DD, defaults to today)countnumber, default10— Number of results to return.pagenumber, default1— Page number.
Examples
// Check ChatGPT's current ranks (unified app).
await af.store.appRanks({ appIds: ["ua_miTXv6"], countries: ["US"] })
// Check ChatGPT's current ranks on one storefront.
await af.store.appRanks({ appIds: [336744124021], countries: ["US"] })
// Compare ChatGPT's ranks across the US, UK, and Japan.
await af.store.appRanks({ appIds: ["ua_miTXv6"], countries: ["US","GB","JP"] })
// Check Procreate's paid iPad chart ranks.
await af.store.appRanks({ appIds: ["ua_CxA1MS"], subtypes: ["paid"], deviceTypes: ["tablet"], countries: ["US"] })
// Trace ChatGPT's chart history through December 2025.
await af.store.appRanks({ appIds: ["ua_miTXv6"], granularity: "daily", start: "2025-12-01", end: "2025-12-31", countries: ["US"] })
// Check ChatGPT's rank in one category (US iOS Productivity).
await af.store.appRanks({ appIds: [336744124021], categoryIds: [6007], countries: ["US"] })List the top apps in a category chart for a given country and category, with current positions and day-over-day deltas.
Note
For the inverse (e.g., "where does Minecraft rank in UK Games?"), see af.store.appRanks.
Parameters
countryrequiredstring— ISO country code (e.g. US, JP, GB)categoryIdrequirednumber— Category IDs come fromaf.store.categories.subtype"free" | "paid" | "topgrossing", default"free"— Category subtype (chart variant within the category).datestring— Snapshot date (YYYY-MM-DD, defaults to current).countnumber, default10— Number of results to return.pagenumber, default1— Page number.
Examples
// Find the Games category, then pull its US chart.
await af.store.categories({ q: "games" })
await af.store.topCharts({ country: "US", categoryId: 6014 })
// List top paid apps on the US App Store.
await af.store.topCharts({ country: "US", categoryId: 25204, subtype: "paid" })
// List top free apps on the Japan App Store.
await af.store.topCharts({ country: "JP", categoryId: 25204 })
// List top free apps on Google Play in the US.
await af.store.topCharts({ country: "US", categoryId: 100 })
// List top free apps on the US App Store in December 2025.
await af.store.topCharts({ country: "US", categoryId: 25204, date: "2025-12-01" })List every store category with its ID. Numeric category IDs required by af.store.appRanks({ categoryIds }) and af.store.topCharts({ categoryId }) are available here.
Parameters
countnumber, default50— Number of results to return.pagenumber, default1— Page number.qstring— Filter byname.sort"name"— Field to sort by. Omit to order by relevance whenqis set, otherwise list order.order"asc" | "desc", default"desc"— Sort direction.categoryIdnumber[]— Only return these category IDs.parentIdnumber— Only include subcategories of this parent category (drill-down by id).storefrontstring[]— Only include categories from these storefronts (e.g.apple:ios,google_play).deviceTypestring[]— Only include categories for these device types (e.g.handheld,tablet).allboolean, defaultfalse— Include non-rank stores (roku, vizio, etc.). These have categories but no rank data.
Examples
// Find the Games category.
await af.store.categories({ q: "games" })
// List every Apple iOS category.
await af.store.categories({ storefront: ["apple:ios"] })
// List subcategories of a parent category (here, Apple Games).
await af.store.categories({ parentId: 6014 })
// Include categories from non-rank-supporting stores (e.g. Roku, Vizio) (not common).
await af.store.categories({ all: true })List featured and editorial placements for an app or storefront product. Request 0 rows for summary stats only.
Note
Today tab, stories, collections, and similar curated placements. Pass a unified app ID to cover every storefront with app-intelligence coverage, or a numeric product ID for one storefront. Without a date range, covers the last 30 days.
Parameters
appIdrequirednumber | string— The app's unified app ID or product ID.countriesstring[]— Countries to include. Omit to query US only, or pass multiple to compare markets. To include every country, setallCountriesinstead.allCountriesboolean, defaultfalse— Include every country. Cannot be combined withcountries.includeRankTrendboolean, defaultfalse— Include per-interval rank_trend for each placement.sort"relevance" | "date", default"relevance"— Sort placements by relevance or date.order"asc" | "desc", default"desc"— Sort direction.startstring— Start date (YYYY-MM-DD)endstring— End date (YYYY-MM-DD, defaults to today). Spans at most 31 days.countnumber, default10— Number of results to return.pagenumber, default1— Page number.
Examples
// List Minecraft's recent featured placements (unified app).
await af.store.featured({ appId: "ua_X7iNgb" })
// List Minecraft's recent featured placements on one storefront.
await af.store.featured({ appId: 10157213 })
// Compare Minecraft's placement coverage across the US, UK, and Japan.
await af.store.featured({ appId: "ua_X7iNgb", countries: ["US","GB","JP"] })
// List Minecraft's placements during a specific month (December 2025).
await af.store.featured({ appId: "ua_X7iNgb", start: "2025-12-01", end: "2025-12-31" })
// List Minecraft's placements with rank history.
await af.store.featured({ appId: "ua_X7iNgb", includeRankTrend: true })
// List Minecraft's placements sorted by end date, newest run first.
await af.store.featured({ appId: "ua_X7iNgb", sort: "date", order: "desc" })
// Get Minecraft's placement summary only.
await af.store.featured({ appId: "ua_X7iNgb", count: 0 })Read the full store listing for one storefront: localized text (name, subtitle, description, release notes) plus screenshots, video, categories, monetization, supported devices, country availability, price, file size, and age rating. Takes a numeric product ID (one storefront at a time; a unified app has one product per storefront). One locale per request.
Note
Everything visible on one app's store page, resolved to one locale. The response includes sibling_products (product IDs for the same app on other storefronts); one request covers one listing. Filtering or searching listings across the catalog (e.g. "apps whose description mentions X") lives in af.explorer.listProducts. Identity/publisher/member-products data lives in af.apps.get.
Parameters
productIdrequirednumber— Numeric product ID for one storefront. Not a unified app ID. Member product_id values are available fromaf.apps.get({ appId: "<unified-app-id>" }).languagestring— Locale (e.g. en, ja, zh-Hans) for name, subtitle, description, release notes, and screenshots. Defaults to en; falls back to the first available locale when the requested one has no metadata. The response echoes the resolved language.deviceType"watch" | "handheld" | "tablet" | "tv" | "desktop" | "headset", default"handheld"— Relevant to Apple apps. Pick handheld for iPhone-specific metadata, tablet for iPad, desktop for Mac, etc.
Examples
// Read Minecraft's store listing.
await af.store.appListing({ productId: 10157213 })
// Read Minecraft's Japanese-localized listing.
await af.store.appListing({ productId: 10157213, language: "ja" })
// Read Minecraft's iPad screenshots.
await af.store.appListing({ productId: 10157213, deviceType: "tablet" })Read an app's audience demographics: the estimated age and gender breakdown.
Note
Returns who the audience is (age, gender). For what else that audience uses, see af.audience.crossUsage. For the app's performance numbers (downloads, revenue, ratings), use af.metrics.query for trends over time or af.explorer.listProducts for a current snapshot.
Parameters
appIdrequirednumber | string— The app's unified app ID or product ID.
Examples
// Read Minecraft's audience across all its storefronts (unified app ID).
await af.audience.demographics({ appId: "ua_X7iNgb" })
// Read Minecraft's audience on Google Play only (product ID).
await af.audience.demographics({ appId: 6938219 })Find the apps that an app's users also use.
Note
Competitive and partnership intel. For that app's own audience makeup (age, gender), use af.audience.demographics.
Parameters
appIdrequirednumber | string— The app's unified app ID or product ID.countnumber, default10— Number of results to return.pagenumber, default1— Page number.
Examples
// Find the apps ChatGPT's users also use (unified app ID).
await af.audience.crossUsage({ appId: "ua_miTXv6" })
// Find the apps ChatGPT's users also use on the App Store only (product ID).
await af.audience.crossUsage({ appId: 336744124021 })Read individual reviews for one or more apps. Returns review text, star rating, country, and app version. Filterable by star rating, date range, country, version, and tracking relationship.
Note
Reviews are public, so this works for any app (with the right plan), not just those the account tracks; with no app filter, results cover every tracked app. For volume counts by dimension, see af.reviews.breakdown. To respond to a review, use af.reviews.reply (write access requires owning the app).
Parameters
stars(1 | 2 | 3 | 4 | 5)[]— Filter by star rating.versionsstring[]— Filter by app version. Pass multiple to combine.countriesstring[]— Filter to one or more ISO country codes (e.g. US, JP, GB).qstring— Search review title and body. Pass multiple keywords to match any. Case-insensitive; combines with other filters.sort"date" | "stars"— Sort by review date or star rating.order"asc" | "desc", default"desc"— Sort direction.filterAppsById(number | string)[]— Only include data about specific apps, by product ID or unified app ID. Takes precedence over the otherfilterAppsBy*keys when set. Storefront, source, or type filters are better for app sets that can be described by those criteria.filterAppsByStorefrontstring[]— Narrow the account's tracked apps to those on these storefronts (e.g. apple:ios, google_play).filterAppsBySource("own" | "shared" | "manual")[]— Narrow the account's tracked apps by tracking relationship.filterAppsByType("app" | "bundle" | "inapp" | "subscription")[]— Narrow the account's tracked apps to products of these types.startstring— Start date (YYYY-MM-DD)endstring— End date (YYYY-MM-DD, defaults to today)countnumber, default10— Number of results to return.pagenumber, default1— Page number. 1-500.
Examples
// Read Minecraft's recent reviews.
await af.reviews.list({ filterAppsById: ["ua_X7iNgb"] })
// Read Minecraft's 5-star reviews.
await af.reviews.list({ filterAppsById: ["ua_X7iNgb"], stars: [5] })
// Compare Minecraft's reviews across the US, Japan, and the UK.
await af.reviews.list({ filterAppsById: ["ua_X7iNgb"], countries: ["US","JP","GB"] })
// Read Minecraft's December 2025 reviews.
await af.reviews.list({ filterAppsById: ["ua_X7iNgb"], start: "2025-12-01", end: "2025-12-31" })
// Page through long results across your own apps.
await af.reviews.list({ filterAppsBySource: ["own"], count: 50, page: 2 })Aggregate review counts for one or more apps, bucketed by dimension. Returns one count per dimension value, plus a global total across the matched set.
Note
Reviews are public, so this works for any app (with the right plan), not just those the account tracks; with no app filter, counts cover every tracked app. Without a date range, covers the last 30 days. For individual review text, use af.reviews.list.
Parameters
stars(1 | 2 | 3 | 4 | 5)[]— Filter by star rating.versionsstring[]— Filter by app version. Pass multiple to combine.countriesstring[]— Filter to one or more ISO country codes (e.g. US, JP, GB).qstring— Search review title and body. Pass multiple keywords to match any. Case-insensitive; combines with other filters.filterAppsById(number | string)[]— Only include data about specific apps, by product ID or unified app ID. Takes precedence over the otherfilterAppsBy*keys when set. Storefront, source, or type filters are better for app sets that can be described by those criteria.filterAppsByStorefrontstring[]— Narrow the account's tracked apps to those on these storefronts (e.g. apple:ios, google_play).filterAppsBySource("own" | "shared" | "manual")[]— Narrow the account's tracked apps by tracking relationship.filterAppsByType("app" | "bundle" | "inapp" | "subscription")[]— Narrow the account's tracked apps to products of these types.startstring— Start date (YYYY-MM-DD)endstring— End date (YYYY-MM-DD, defaults to today)by("stars" | "country" | "version" | "language" | "product" | "response" | "deleted" | "tag")[]— Limit the response to these dimensions; omit to return all.topnumber, default20— Maximum values returned per dimension; the rest are summed under__other__.
Examples
// Break down Minecraft's recent reviews.
await af.reviews.breakdown({ filterAppsById: ["ua_X7iNgb"] })
// Where are Minecraft's biggest fans writing from?
await af.reviews.breakdown({ filterAppsById: ["ua_X7iNgb"], stars: [5] })
// Count Minecraft's December 2025 5-star reviews.
await af.reviews.breakdown({ filterAppsById: ["ua_X7iNgb"], stars: [5], start: "2025-12-01", end: "2025-12-31" })
// How many Minecraft reviewers raved?
await af.reviews.breakdown({ filterAppsById: ["ua_X7iNgb"], q: "love amazing fun great best" })
// Compare review volume across your own apps.
await af.reviews.breakdown({ filterAppsBySource: ["own"] })Warning
Mutation (create) — refuses without confirmMutation.
Post or withdraw a developer response on a specific review. Pass content to post; pass delete: true to withdraw a previously-posted response. Returns the resulting state (published/pending for a post, removed/removal_pending for a withdrawal) along with the submitting account.
Note
Write access only: the account must own the app the review is on. Review IDs come from af.reviews.list; pass the row's review_id. Stores may queue the action (pending / removal_pending); re-fetch with af.reviews.list later to confirm.
Parameters
reviewIdrequiredstring— Review to act on. Usereview_idfromaf.reviews.list.contentstring— Response text the developer wants to publish.deleteboolean— Withdraw the previously-posted response on this review. Mutually exclusive withcontent.
Examples
// Reply to a low-star review after shipping a fix.
await af.reviews.reply({ reviewId: "rev123", content: "We just shipped a fix in v2.1. Let us know if you still see this." })
// Withdraw a previously-posted response.
await af.reviews.reply({ reviewId: "rev123", delete: true })Check the organic keywords one or more apps rank for, with position, popularity, and competitiveness.
Note
For the inverse (apps that rank for a keyword), see af.keywords.rankingApps. This works for any app (with the right plan), not just those the account tracks; with no app filter, covers every tracked app.
Parameters
productIdsnumber[]— Product identifiers (numeric, one storefront each).countriesrequiredstring[]— One or more ISO country codes (e.g. US, JP, GB). Pass several to compare markets.deviceType"watch" | "handheld" | "tablet" | "tv" | "desktop" | "headset"— Device typecountnumber, default10— Number of results to return (min 10).pagenumber, default1— Page number.
Examples
// Check ChatGPT's current US keyword rankings.
await af.keywords.organic({ productIds: [336744124021], countries: ["US"] })
// Check ChatGPT's iPad-only keyword rankings.
await af.keywords.organic({ productIds: [336744124021], countries: ["US"], deviceType: "tablet" })
// Compare ChatGPT and Gemini's US keyword rankings.
await af.keywords.organic({ productIds: [336744124021,337217072531], countries: ["US"] })List the paid keywords one or more apps run ads on, with impression share and organic rank.
Note
Organic keyword rankings are in af.keywords.organic.
Parameters
productIdsrequirednumber[]— Product identifiers (numeric, one storefront each).daysnumber, default180— Lookback period in days. Common values: 7, 14, 30, 90, 180, 365.countriesrequiredstring[]— One or more ISO country codes (e.g. US, JP, GB). Pass several to compare markets.deviceTypes("watch" | "handheld" | "tablet" | "tv" | "desktop" | "headset")[]— Filter by device type. Defaults to handheld.countnumber, default10— Number of results to return (min 10).pagenumber, default1— Page number.
Examples
// Find Headspace's US paid keywords.
await af.keywords.paid({ productIds: [15250929], countries: ["US"] })
// Compare Headspace's and Calm's US paid keywords.
await af.keywords.paid({ productIds: [15250929,304554144], countries: ["US"] })
// Find Headspace's paid keywords across the US, UK, and Japan.
await af.keywords.paid({ productIds: [15250929], countries: ["US","GB","JP"] })
// Find Headspace's US iPad paid keywords.
await af.keywords.paid({ productIds: [15250929], countries: ["US"], deviceTypes: ["tablet"] })
// Check Headspace's US paid keywords over the last 30 days.
await af.keywords.paid({ productIds: [15250929], countries: ["US"], days: 30 })View where all your tracked keywords rank for a single app+country combo, with each keyword's current position, movement since it last changed, starting position, popularity, and competitiveness.
Note
To trace one keyword's rank over time for an app+country combo, use af.keywords.trackedTrend. For a point-in-time list of every keyword any app ranks for, use af.keywords.organic. Add more tracked keywords with af.keywords.track.
Parameters
productIdrequirednumber— Numeric product ID for one storefront. Not a unified app ID. Member product_id values are available fromaf.apps.get({ appId: "<unified-app-id>" }).countryrequiredstring— ISO country code (e.g. US, JP, GB)deviceType"watch" | "handheld" | "tablet" | "tv" | "desktop" | "headset"— Device to read ranks for. Omit to use the store default.countnumber, default10— Number of results to return (min 10).pagenumber, default1— Page number.sort"position" | "popularity" | "competitiveness" | "num_apps" | "keyword_term" | "delta"— Field to order results by.order"asc" | "desc", default"desc"— Sort direction.startstring— Start of the window (YYYY-MM-DD). Omit the range for the last 7 days; the rank on the start date is the starting-position baseline.endstring— End of the window (YYYY-MM-DD, defaults to today). Spans at most 31 days.keywordTermstring— Only include tracked keywords whose term contains this text.minPositionnumber— Best rank to include (1 = top).maxPositionnumber— Worst rank to include.minPopularitynumber— Lowest popularity to include (0-100).maxPopularitynumber— Highest popularity to include (0-100).minCompetitivenessnumber— Lowest competitiveness to include (0-100).maxCompetitivenessnumber— Highest competitiveness to include (0-100).
Examples
// Check how ChatGPT's tracked keywords are ranking.
await af.keywords.trackedRanks({ productId: 336744124021, country: "US" })
// List ChatGPT's best-ranking keywords first.
await af.keywords.trackedRanks({ productId: 336744124021, country: "US", sort: "position", order: "asc" })
// Show only the keywords ChatGPT ranks in the top 10.
await af.keywords.trackedRanks({ productId: 336744124021, country: "US", maxPosition: 10 })
// Find the most-searched keywords ChatGPT should prioritize.
await af.keywords.trackedRanks({ productId: 336744124021, country: "US", sort: "popularity", minPopularity: 50 })
// Trace ChatGPT's keyword movement across a custom week.
await af.keywords.trackedRanks({ productId: 336744124021, country: "US", start: "2026-01-06", end: "2026-01-12" })
// Page through a long tracked keyword set.
await af.keywords.trackedRanks({ productId: 336744124021, country: "US", page: 2 })Trace how one tracked keyword's rank changes over time for a single app+country combo. Each point gives the rank and how many positions it moved since the one before.
Note
For all of an app's tracked keywords at once, use af.keywords.trackedRanks.
Parameters
productIdrequirednumber— Numeric product ID for one storefront. Not a unified app ID. Member product_id values are available fromaf.apps.get({ appId: "<unified-app-id>" }).countryrequiredstring— ISO country code (e.g. US, JP, GB)deviceType"watch" | "handheld" | "tablet" | "tv" | "desktop" | "headset"— Device to read ranks for. Omit to use the store default.keywordIdrequiredstring— The keyword to trace. Must be tracked for this app and country; its opaque id comes fromaf.keywords.trackedRanksoraf.keywords.tracked.granularity"daily" | "hourly", default"daily"— Sampling rate.startstring— Start of the window (YYYY-MM-DD). Omit the range for the last 7 days.endstring— End of the window (YYYY-MM-DD, defaults to today). Spans at most 14 days for hourly granularity, 31 for daily.
Examples
// Find a tracked keyword, then trace its rank day by day.
await af.keywords.trackedRanks({ productId: 336744124021, country: "US" })
await af.keywords.trackedTrend({ keywordId: "00f2b1ead3a0990b818517356cb40280", productId: 336744124021, country: "US" })
// Trace a keyword's rank for ChatGPT across a specific week.
await af.keywords.trackedTrend({ keywordId: "00f2b1ead3a0990b818517356cb40280", productId: 336744124021, country: "US", start: "2026-01-06", end: "2026-01-12" })
// Trace a keyword hour by hour.
await af.keywords.trackedTrend({ keywordId: "00f2b1ead3a0990b818517356cb40280", productId: 336744124021, country: "US", granularity: "hourly" })Discover keyword ideas to consider targeting for a single app+country combo, ranked by relevance to the app and including some drawn from apps you compete with. Each comes with its popularity, competitiveness, and the app's current rank.
Note
Works for any app, not just tracked ones. For the keywords an app already ranks for, use af.keywords.organic.
Parameters
productIdrequirednumber— Numeric product ID for one storefront. Not a unified app ID. Member product_id values are available fromaf.apps.get({ appId: "<unified-app-id>" }).countryrequiredstring— ISO country code (e.g. US, JP, GB)deviceType"watch" | "handheld" | "tablet" | "tv" | "desktop" | "headset"— Device to read ranks for. Omit to use the store default.countnumber, default10— Number of results to return.pagenumber, default1— Page number.
Examples
// Discover keywords ChatGPT should consider targeting.
await af.keywords.suggestions({ productId: 336744124021, country: "US" })
// Find keyword ideas for ChatGPT in Japan.
await af.keywords.suggestions({ productId: 336744124021, country: "JP" })
// Pull a broader set of suggestions.
await af.keywords.suggestions({ productId: 336744124021, country: "US", count: 50 })List the apps ranking for a specific keyword in organic search, plus the keyword's own popularity and competitiveness scores.
Note
For a specific app's keyword positions, see af.keywords.organic. For related search terms to brainstorm, see af.keywords.related.
Parameters
keywordTermrequiredstring— Keyword to look up.countryrequiredstring— ISO country code (e.g. US, JP, GB)storefrontrequiredstring— App store platform (e.g. apple:ios, google_play, amazon_appstore, steam, windows10, apple:mac, apple:tv, apple:imessage, or another supported storefront).deviceType"watch" | "handheld" | "tablet" | "tv" | "desktop" | "headset"— Device typecountnumber, default10— Number of results to return.pagenumber, default1— Page number.
Examples
// Find US iOS apps ranking for "fitness".
await af.keywords.rankingApps({ keywordTerm: "fitness", country: "US", storefront: "apple:ios" })
// Find Google Play apps ranking for "fitness".
await af.keywords.rankingApps({ keywordTerm: "fitness", country: "US", storefront: "google_play" })
// Find US iPad apps ranking for "meditation".
await af.keywords.rankingApps({ keywordTerm: "meditation", country: "US", storefront: "apple:ios", deviceType: "tablet" })List the apps advertising on a specific keyword, with each advertiser's impression share, organic rank, and how long they've been bidding.
Note
For the apps that rank organically on the same term, see af.keywords.rankingApps.
Parameters
keywordTermrequiredstring— Keyword to look up advertisers fordaysnumber, default180— Lookback period in days. Common values: 7, 14, 30, 90, 180, 365.countryrequiredstring— ISO country code (e.g. US, JP, GB)deviceType"watch" | "handheld" | "tablet" | "tv" | "desktop" | "headset"— Device typecountnumber, default10— Number of results to return.pagenumber, default1— Page number.
Examples
// Find US apps advertising on the "notion" brand.
await af.keywords.advertisers({ keywordTerm: "notion", country: "US" })
// Find US iPad apps advertising on "meditation".
await af.keywords.advertisers({ keywordTerm: "meditation", country: "US", deviceType: "tablet" })
// Find US apps advertising on "fitness" over the last 30 days.
await af.keywords.advertisers({ keywordTerm: "fitness", country: "US", days: 30 })Find keywords related to a seed term for ASO research. Useful for finding alternatives with a similar audience that are more popular or less competitive.
Note
For apps that rank on a keyword, see af.keywords.rankingApps.
Parameters
keywordTermrequiredstring— Seed keyword to find related terms for.countryrequiredstring— ISO country code (e.g. US, JP, GB)storefrontrequiredstring— App store platform (e.g. apple:ios, google_play, amazon_appstore, steam, windows10, apple:mac, apple:tv, apple:imessage, or another supported storefront).deviceType"watch" | "handheld" | "tablet" | "tv" | "desktop" | "headset"— Device typecountnumber, default10— Number of results to return.pagenumber, default1— Page number.
Examples
// Find US iOS keywords related to "fitness".
await af.keywords.related({ keywordTerm: "fitness", country: "US", storefront: "apple:ios" })
// Find US Google Play keywords related to "fitness".
await af.keywords.related({ keywordTerm: "fitness", country: "US", storefront: "google_play" })
// Find US iPad keywords related to "meditation".
await af.keywords.related({ keywordTerm: "meditation", country: "US", storefront: "apple:ios", deviceType: "tablet" })List tracked keywords with their opaque IDs.
Note
Reference a keyword by its stable keyword_id, not its term text.
Parameters
countnumber, default10— Number of results to return.pagenumber, default1— Page number.qstring— Filter bykeyword_term.sort"keyword_term" | "active" | "added_on"— Field to sort by. Omit to order by relevance whenqis set, otherwise list order.order"asc" | "desc", default"desc"— Sort direction.includeRelationshipsboolean, defaultfalse— Include per-(product, country) tracking detail and sync state on each row. Off by default; adds a nested block per tracked (product, country) pair.
Examples
// List every tracked keyword.
await af.keywords.tracked()
// Search tracked keywords for "fitness".
await af.keywords.tracked({ q: "fitness" })
// List the most-recently-tracked keywords first.
await af.keywords.tracked({ sort: "added_on" })
// Show each keyword's tracking and sync detail.
await af.keywords.tracked({ includeRelationships: true })Warning
Mutation (create) — refuses without confirmMutation.
Track a keyword to monitor your app's hourly rank for it over time and get automatic alerts when its position moves.
Note
Product IDs for owned apps are available from af.apps.tracked.
Parameters
productIdrequirednumber— Product ID of the app to track the keyword forkeywordTermrequiredstring— Keyword to start trackingcountryrequiredstring— ISO country code (e.g. US, JP, GB)
Examples
// Start tracking "meditation" for one of your apps in the US.
await af.keywords.track({ keywordTerm: "meditation", productId: 336744124021, country: "US" })
// Track "workout" in Japan.
await af.keywords.track({ keywordTerm: "workout", productId: 336744124021, country: "JP" })Warning
Mutation (destructive) — refuses without confirmMutation.
Stop tracking a keyword.
Note
Keyword IDs are opaque hashes on each record from af.keywords.tracked.
Parameters
keywordIdrequiredstring— Identifier of a tracked keyword row (returned byaf.keywords.tracked). Not the keyword text.
Examples
// Stop tracking a keyword.
await af.keywords.untrack({ keywordId: "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" })List the Apple Ads organizations you manage campaigns in, with each one's currency and timezone.
Note
The organization_id on each row is what af.appleAds.campaigns rows reference.
Parameters
countnumber, default10— Number of results to return.pagenumber, default1— Page number.
Examples
// List all the Apple Ads organizations you manage.
await af.appleAds.organizations()List your Apple Ads campaigns with each one's status, budget, targeted countries, and schedule.
Note
Each row's product_id is the advertised app. Resolve its name with af.apps.get.
Parameters
displayStatus"running" | "on_hold" | "paused" | "deleted"— Filter to campaigns in one status. Omit to include all statuses.namestring— Filter to campaigns whose name contains this text.countriesstring[]— Filter to campaigns targeting any of these countries.countnumber, default10— Number of results to return.pagenumber, default1— Page number.
Examples
// List all your Apple Ads campaigns.
await af.appleAds.campaigns()
// List only your running campaigns.
await af.appleAds.campaigns({ displayStatus: "running" })
// Search your campaigns by name.
await af.appleAds.campaigns({ name: "Brand" })
// List campaigns targeting the US or UK.
await af.appleAds.campaigns({ countries: ["US","GB"] })List Apple Ads ad groups with each one's default bid, CPA cap, pricing model, and schedule.
Note
Scope to one campaign from af.appleAds.campaigns. Its bid keywords live in af.appleAds.keywords.
Parameters
campaignIdstring— Scope to ad groups in one campaign.displayStatus"running" | "on_hold" | "paused" | "deleted"— Filter to ad groups in one status. Omit to include all statuses.namestring— Filter to ad groups whose name contains this substring.countnumber, default10— Number of results to return.pagenumber, default1— Page number.
Examples
// List all your ad groups across every campaign.
await af.appleAds.adGroups()
// List the ad groups in one campaign.
await af.appleAds.adGroups({ campaignId: "aac_W9YthU" })List a campaign's bid keywords with each keyword's performance (impressions, taps, installs, spend, cost-per-install) over a date range, plus its match type, bid, and whether it's a targeting or negative term.
Note
Get campaign IDs from af.appleAds.campaigns and ad groups from af.appleAds.adGroups. Omitting the range covers the last 30 days.
Parameters
campaignIdrequiredstring— Campaign whose bid keywords to list.adGroupIdstring— Filter to keywords in one ad group.status"active" | "paused" | "deleted"— Filter to keywords in one status. Omit to include all statuses.matchType"broad" | "exact"— Filter to one match type. Omit to include both.namestring— Filter to keywords whose text contains this substring.sort"spend" | "impressions" | "taps" | "installs" | "cpa" | "cvr" | "bid_amount"— Order keywords by a performance metric or the bid. Omit for newest first.order"asc" | "desc", default"desc"— Sort direction.startstring— Start date (YYYY-MM-DD)endstring— End date (YYYY-MM-DD, defaults to today)countnumber, default10— Number of results to return.pagenumber, default1— Page number.
Examples
// Find a running campaign, then list its bid keywords.
await af.appleAds.campaigns({ displayStatus: "running" })
await af.appleAds.keywords({ campaignId: "aac_W9YthU" })
// See how a campaign's keywords performed over July 2026.
await af.appleAds.keywords({ campaignId: "aac_W9YthU", start: "2026-07-01", end: "2026-07-31" })
// Find a campaign's highest-spending keywords.
await af.appleAds.keywords({ campaignId: "aac_W9YthU", sort: "spend" })List the actual user search terms that triggered a campaign's ads, each with its all-time performance (impressions, taps, installs, spend, cost-per-install). Use these to discover new keywords to bid on or exclude.
Note
Get campaign IDs from af.appleAds.campaigns. Bid on a promising term with af.appleAds.addKeywords.
Parameters
campaignIdrequiredstring— Campaign whose search terms to list.countnumber, default10— Number of results to return.pagenumber, default1— Page number.
Examples
// Find a campaign, then see the user searches that triggered its ads.
await af.appleAds.campaigns()
await af.appleAds.searchTerms({ campaignId: "aac_uDGL4v" })Report Apple Ads performance per campaign (impressions, taps, installs, spend, cost-per-install), plus an account-wide total, over a date range.
Note
Resolve campaign names and the advertised app from af.appleAds.campaigns. For one campaign's top-performing keywords, use af.appleAds.topKeywords. Omitting the range reports the last 30 days.
Parameters
campaignIdsstring[]— Limit the report to specific campaigns.startstring— Start date (YYYY-MM-DD)endstring— End date (YYYY-MM-DD, defaults to today)countnumber, default10— Number of results to return.pagenumber, default1— Page number.
Examples
// See how much an install costs across all your campaigns.
await af.appleAds.report()
// Report on July 2026 performance.
await af.appleAds.report({ start: "2026-07-01", end: "2026-07-31" })
// List campaigns, then report on specific ones.
await af.appleAds.campaigns()
await af.appleAds.report({ campaignIds: ["aac_uDGL4v"] })Rank a campaign's top-performing keywords by conversion rate, spend, and installs over a date range. Each list holds the top keywords on one metric.
Note
Get campaign IDs from af.appleAds.campaigns. For metrics across all campaigns, use af.appleAds.report. Omitting the range covers the last 30 days.
Parameters
campaignIdrequiredstring— Campaign to rank keywords for.topnumber, default5— How many keywords to return per ranking (max 10).startstring— Start date (YYYY-MM-DD)endstring— End date (YYYY-MM-DD, defaults to today)
Examples
// Find a campaign, then see its top-performing keywords.
await af.appleAds.campaigns()
await af.appleAds.topKeywords({ campaignId: "aac_uDGL4v" })
// Rank a campaign's keywords for a specific week.
await af.appleAds.topKeywords({ campaignId: "aac_uDGL4v", start: "2026-07-25", end: "2026-07-31" })
// Widen each ranking to the maximum of 10 keywords.
await af.appleAds.topKeywords({ campaignId: "aac_uDGL4v", top: 10 })List every known SDK with its id, or search to find a specific one.
Parameters
countnumber, default50— Number of results to return.pagenumber, default1— Page number.qstring— Filter byname,description,tags.sort"name" | "active"— Field to sort by. Omit to order by relevance whenqis set, otherwise list order.order"asc" | "desc", default"desc"— Sort direction.sdkIdstring[]— Only return these SDK ids.includeInactiveboolean, defaultfalse— Include inactive SDKs. Rare; most callers want active only.
Examples
// Find OneSignal's id.
await af.sdks.list({ q: "OneSignal" })
// Search for analytics SDKs.
await af.sdks.list({ q: "analytics" })
// Look up details for several SDK ids.
await af.sdks.list({ sdkId: ["firebase","admob","onesignal"] })
// Include inactive SDKs in the listing (not common).
await af.sdks.list({ includeInactive: true })