> AI agents: this is one page from PostHog's docs. Full index of Markdown docs for LLMs: https://posthog.com/llms.txt # Linking Apple (App Store Connect) as a source Canonical URL: https://posthog.com/docs/data-pipelines/sources/app-store-connect > **Cloud region:** This page uses US Cloud hosts. For an EU Cloud project, use `https://eu.posthog.com` instead of `https://us.posthog.com` or `https://app.posthog.com` (app host for links). ## On this page - [Prerequisites](#prerequisites) - [Adding a data source](#adding-a-data-source) - [Sync modes](#sync-modes) - [Configuration](#configuration) - [Supported tables](#supported-tables) - [Troubleshooting](#troubleshooting) ![](https://res.cloudinary.com/dmukukwp6/image/upload/texture_tan_9608fcca70) ![](https://res.cloudinary.com/dmukukwp6/image/upload/texture_tan_dark_a92b0e022d) Let AI connect your sources for you Skip the manual setup — run this in your project and the wizard auto-detects your databases and APIs and connects them to PostHog. `npx @posthog/wizard warehouse` ![PostHog Wizard hedgehog](https://res.cloudinary.com/dmukukwp6/image/upload/wizard_3f8bb7a240.png) ![](https://res.cloudinary.com/dmukukwp6/image/upload/wizard_3f8bb7a240.png)Let AI connect your sources for you The Apple (App Store Connect) connector syncs apps, app store versions, builds, and more into the PostHog data warehouse, so you can analyze them alongside your product data. ## Prerequisites Credentials that can read the data you want to sync. PostHog only reads data, so read access is enough. ## Adding a data source 1. In PostHog, go to the [Sources tab](https://app.posthog.com/data-management/sources) of the data pipeline section. 2. Click **\+ New source** and click **Link** next to this source. 3. Enter your credentials (see [Configuration](#configuration) below) and click **Next**. 4. Select the tables you want to sync, choose a sync method and frequency, then click **Import**. Once the syncs are complete, you can start querying this data in PostHog. Pull your App Store apps, versions, builds, reviews and sales reports. An **Account Holder** or **Admin** creates an API key under **Users and Access → Integrations → App Store Connect API** in App Store Connect. Set the key's access role there - it decides which tables sync. Copy the issuer ID and key ID from that page, then paste the contents of the `.p8` private key file you download. Apple only lets you download that file once, so keep a copy. Sales and subscription reports also need your vendor number (App Store Connect → **Payments and Financial Reports**) and a key with the **Finance**, **Sales**, or **Admin** role. Leave it blank if you only want app, review and build data. The analytics tables need a key with the Admin role. Apple lets only an Admin key start an analytics report. Leave **app IDs** blank to sync every app the key can read. To sync only some of your apps, list their Apple IDs, separated by commas. You can find an app's Apple ID in App Store Connect under **App Information → General Information**. The filter covers the apps, versions, reviews, review responses, in-app purchases, subscription groups and analytics tables. Builds, TestFlight groups and the sales reports cover your whole account, so they are not filtered. Analytics report tables keep every restatement Apple publishes for a report date (about six days of revisions), so a raw `SUM` grouped by date overcounts. The raw rows preserve the restatement history; to aggregate, keep only the latest restatement per report date and dimension combination, for example: ``` SELECT raw.date, raw.app_id, raw.app_name, raw.app_apple_identifier, raw.app_version, raw.device, raw.platform_version, raw.source_type, raw.page_type, raw.app_download_date, raw.territory, argMax(raw.sessions, raw.processing_date) AS sessions, argMax(raw.total_session_duration, raw.processing_date) AS total_session_duration, argMax(raw.unique_devices, raw.processing_date) AS unique_devices FROM appstoreconnect_analytics_app_sessions AS raw INNER JOIN ( SELECT app_id, date, max(processing_date) AS processing_date FROM appstoreconnect_analytics_app_sessions GROUP BY app_id, date ) AS latest ON raw.app_id = latest.app_id AND raw.date = latest.date AND raw.processing_date = latest.processing_date GROUP BY raw.date, raw.app_id, raw.app_name, raw.app_apple_identifier, raw.app_version, raw.device, raw.platform_version, raw.source_type, raw.page_type, raw.app_download_date, raw.territory ``` This query names the table as connected without a table name prefix; if you set one, add it wherever the table name appears. Each analytics table's description carries the exact query for that table. You'll be asked for: - **Issuer ID**: for example `57246542-96fe-1a63-e053-0824d011072a`. - **Key ID**: for example `2X9R4HXF34`. - **Private key (.p8 contents)**: for example `-----BEGIN PRIVATE KEY-----`. ## Sync modes Each table can be synced in one of several modes, depending on what the source supports: - **Webhook** (when available) – the source pushes changes to PostHog in real time. Fastest freshness, lowest ongoing cost, and the only mode that reliably captures updates and deletes. - **Incremental** – only new or updated rows are synced on each run, using a cursor field (such as an `updated_at` timestamp). Cheaper than a full refresh, but deletes aren't captured. - **Append only** – new rows are appended using a cursor field; existing rows are never updated. Ideal for immutable, append-only tables like event logs. - **Full refresh** – the whole table is reloaded on every sync. Use it when a table has no reliable cursor or when you need deletions reflected. See [sync methods](https://posthog.com/docs/data-pipelines/sources.md#sync-methods) for a full explanation of how each mode works and how to choose between them. All Apple (App Store Connect) tables are full refresh. Each sync replaces the contents of the table. ## Configuration | Option | Type | Required | | --- | --- | --- | | `Issuer ID` | text | Yes | | `Key ID` | text | Yes | | `Private key (.p8 contents)` | textarea | Yes | | `Vendor number (optional)` | text | No | | `App IDs (optional)` | text | No | ## Supported tables | Table | Description | Sync method | Incremental field | Primary key | | --- | --- | --- | --- | --- | | `apps` | An app on the App Store, and the parent of the per-app version, review, purchase and subscription tables. | Full refresh | — | id | | `app_store_versions` | A version of an app submitted to the App Store, with its review and release state. | Full refresh | — | app\_id, id | | `builds` | A build uploaded to App Store Connect for TestFlight or App Store release. | Full refresh | — | id | | `beta_groups` | A TestFlight group of beta testers, internal or external, with its public link settings. | Full refresh | — | id | | `customer_reviews` | A customer review left on the App Store, including its star rating and territory. | Full refresh | — | app\_id, id | | `review_responses` | A developer response published to a customer review, one row per responded review. | Full refresh | — | app\_id, id | | `in_app_purchases` | An in-app purchase product configured for an app. | Full refresh | — | app\_id, id | | `subscription_groups` | A group of auto-renewable subscriptions within an app that customers can move between. | Full refresh | — | app\_id, id | | `performance_overviews` | Xcode's aggregated performance metrics for an app, such as launch time, hangs, memory, battery and disk writes, with one row per metric, population and app version. | Full refresh | — | app\_id, category, metric, percentile, device, version | | `sales_reports` | One row of Apple's daily Sales and Trends summary report: units and developer proceeds per SKU, territory and product type. | Incremental, Full refresh | report\_date | report\_date, \_line | | `subscription_reports` | One row of Apple's daily Subscription summary report: active, paid and trial subscription counts by state and territory. | Incremental, Full refresh | report\_date | report\_date, \_line | | `subscription_event_reports` | One row of Apple's daily Subscription Event report: counts of subscription lifecycle events such as renewals, cancellations and plan changes. | Incremental, Full refresh | report\_date | report\_date, \_line | | `analytics_app_sessions` | How often people open the app and for how long, from Apple's App Sessions analytics report. One row per instance line; an instance's rows can restate earlier data dates. Apple restates each report date for about six days, and every restatement is kept as new rows with a later processing\_date, so summing raw rows overcounts. Get one row per report date and dimension combination with: SELECT raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.app\_version, raw.device, raw.platform\_version, raw.source\_type, raw.page\_type, raw.app\_download\_date, raw.territory, argMax(raw.sessions, raw.processing\_date) AS sessions, argMax(raw.total\_session\_duration, raw.processing\_date) AS total\_session\_duration, argMax(raw.unique\_devices, raw.processing\_date) AS unique\_devices FROM appstoreconnect\_analytics\_app\_sessions AS raw INNER JOIN ( SELECT app\_id, date, processing\_date, max(\_line >= 0) AS has\_ongoing\_row FROM appstoreconnect\_analytics\_app\_sessions WHERE (app\_id, date, processing\_date) IN ( SELECT app\_id, date, max(processing\_date) FROM appstoreconnect\_analytics\_app\_sessions GROUP BY app\_id, date ) GROUP BY app\_id, date, processing\_date ) AS latest ON raw.app\_id = latest.app\_id AND raw.date = latest.date AND raw.processing\_date = latest.processing\_date AND (latest.has\_ongoing\_row = 0 OR raw.\_line >= 0) GROUP BY raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.app\_version, raw.device, raw.platform\_version, raw.source\_type, raw.page\_type, raw.app\_download\_date, raw.territory This query names the table as connected without a table name prefix; if you set one, add it wherever the table name appears. | Incremental, Full refresh | processing\_date | app\_id, processing\_date, \_line | | `analytics_app_store_downloads` | How many times people download the app on the App Store, including redownloads and updates, from Apple's App Store Downloads analytics report. Apple restates each report date for about six days, and every restatement is kept as new rows with a later processing\_date, so summing raw rows overcounts. Get one row per report date and dimension combination with: SELECT raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.download\_type, raw.app\_version, raw.device, raw.platform\_version, raw.source\_type, raw.page\_type, raw.pre\_order, raw.territory, argMax(raw.counts, raw.processing\_date) AS counts FROM appstoreconnect\_analytics\_app\_store\_downloads AS raw INNER JOIN ( SELECT app\_id, date, processing\_date, max(\_line >= 0) AS has\_ongoing\_row FROM appstoreconnect\_analytics\_app\_store\_downloads WHERE (app\_id, date, processing\_date) IN ( SELECT app\_id, date, max(processing\_date) FROM appstoreconnect\_analytics\_app\_store\_downloads GROUP BY app\_id, date ) GROUP BY app\_id, date, processing\_date ) AS latest ON raw.app\_id = latest.app\_id AND raw.date = latest.date AND raw.processing\_date = latest.processing\_date AND (latest.has\_ongoing\_row = 0 OR raw.\_line >= 0) GROUP BY raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.download\_type, raw.app\_version, raw.device, raw.platform\_version, raw.source\_type, raw.page\_type, raw.pre\_order, raw.territory This query names the table as connected without a table name prefix; if you set one, add it wherever the table name appears. | Incremental, Full refresh | processing\_date | app\_id, processing\_date, \_line | | `analytics_installations_deletions` | How many times users install and delete the app, from Apple's App Store Installations and Deletions analytics report. Covers users who opted in to sharing data. Apple restates each report date for about six days, and every restatement is kept as new rows with a later processing\_date, so summing raw rows overcounts. Get one row per report date and dimension combination with: SELECT raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.event, raw.download\_type, raw.app\_version, raw.device, raw.platform\_version, raw.source\_type, raw.page\_type, raw.app\_download\_date, raw.territory, argMax(raw.counts, raw.processing\_date) AS counts, argMax(raw.unique\_devices, raw.processing\_date) AS unique\_devices FROM appstoreconnect\_analytics\_installations\_deletions AS raw INNER JOIN ( SELECT app\_id, date, processing\_date, max(\_line >= 0) AS has\_ongoing\_row FROM appstoreconnect\_analytics\_installations\_deletions WHERE (app\_id, date, processing\_date) IN ( SELECT app\_id, date, max(processing\_date) FROM appstoreconnect\_analytics\_installations\_deletions GROUP BY app\_id, date ) GROUP BY app\_id, date, processing\_date ) AS latest ON raw.app\_id = latest.app\_id AND raw.date = latest.date AND raw.processing\_date = latest.processing\_date AND (latest.has\_ongoing\_row = 0 OR raw.\_line >= 0) GROUP BY raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.event, raw.download\_type, raw.app\_version, raw.device, raw.platform\_version, raw.source\_type, raw.page\_type, raw.app\_download\_date, raw.territory This query names the table as connected without a table name prefix; if you set one, add it wherever the table name appears. | Incremental, Full refresh | processing\_date | app\_id, processing\_date, \_line | | `analytics_discovery_engagement` | How users find and interact with the app on the App Store (impressions, page views, taps), from Apple's App Store Discovery and Engagement analytics report. Apple restates each report date for about six days, and every restatement is kept as new rows with a later processing\_date, so summing raw rows overcounts. Get one row per report date and dimension combination with: SELECT raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.event, raw.page\_type, raw.source\_type, raw.engagement\_type, raw.device, raw.platform\_version, raw.territory, argMax(raw.counts, raw.processing\_date) AS counts, argMax(raw.unique\_counts, raw.processing\_date) AS unique\_counts FROM appstoreconnect\_analytics\_discovery\_engagement AS raw INNER JOIN ( SELECT app\_id, date, processing\_date, max(\_line >= 0) AS has\_ongoing\_row FROM appstoreconnect\_analytics\_discovery\_engagement WHERE (app\_id, date, processing\_date) IN ( SELECT app\_id, date, max(processing\_date) FROM appstoreconnect\_analytics\_discovery\_engagement GROUP BY app\_id, date ) GROUP BY app\_id, date, processing\_date ) AS latest ON raw.app\_id = latest.app\_id AND raw.date = latest.date AND raw.processing\_date = latest.processing\_date AND (latest.has\_ongoing\_row = 0 OR raw.\_line >= 0) GROUP BY raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.event, raw.page\_type, raw.source\_type, raw.engagement\_type, raw.device, raw.platform\_version, raw.territory This query names the table as connected without a table name prefix; if you set one, add it wherever the table name appears. | Incremental, Full refresh | processing\_date | app\_id, processing\_date, \_line | | `analytics_app_crashes` | Crash counts by app version and device, from Apple's App Crashes analytics report. Covers users who opted in to sharing data, with low-volume rows suppressed. Apple restates each report date for about six days, and every restatement is kept as new rows with a later processing\_date, so summing raw rows overcounts. Get one row per report date and dimension combination with: SELECT raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.app\_version, raw.device, raw.platform\_version, argMax(raw.crashes, raw.processing\_date) AS crashes, argMax(raw.unique\_devices, raw.processing\_date) AS unique\_devices FROM appstoreconnect\_analytics\_app\_crashes AS raw INNER JOIN ( SELECT app\_id, date, processing\_date, max(\_line >= 0) AS has\_ongoing\_row FROM appstoreconnect\_analytics\_app\_crashes WHERE (app\_id, date, processing\_date) IN ( SELECT app\_id, date, max(processing\_date) FROM appstoreconnect\_analytics\_app\_crashes GROUP BY app\_id, date ) GROUP BY app\_id, date, processing\_date ) AS latest ON raw.app\_id = latest.app\_id AND raw.date = latest.date AND raw.processing\_date = latest.processing\_date AND (latest.has\_ongoing\_row = 0 OR raw.\_line >= 0) GROUP BY raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.app\_version, raw.device, raw.platform\_version This query names the table as connected without a table name prefix; if you set one, add it wherever the table name appears. | Incremental, Full refresh | processing\_date | app\_id, processing\_date, \_line | | `analytics_app_store_preorders` | Pre-orders placed and canceled for the app, from Apple's App Store Pre-orders analytics report. Apple restates each report date for about six days, and every restatement is kept as new rows with a later processing\_date, so summing raw rows overcounts. Get one row per report date and dimension combination with: SELECT raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.device, raw.platform\_version, raw.source\_type, raw.page\_type, raw.territory, raw.pre\_order\_start\_date, raw.pre\_order\_end\_date, argMax(raw.pre\_orders\_placed, raw.processing\_date) AS pre\_orders\_placed, argMax(raw.pre\_orders\_canceled, raw.processing\_date) AS pre\_orders\_canceled FROM appstoreconnect\_analytics\_app\_store\_preorders AS raw INNER JOIN ( SELECT app\_id, date, processing\_date, max(\_line >= 0) AS has\_ongoing\_row FROM appstoreconnect\_analytics\_app\_store\_preorders WHERE (app\_id, date, processing\_date) IN ( SELECT app\_id, date, max(processing\_date) FROM appstoreconnect\_analytics\_app\_store\_preorders GROUP BY app\_id, date ) GROUP BY app\_id, date, processing\_date ) AS latest ON raw.app\_id = latest.app\_id AND raw.date = latest.date AND raw.processing\_date = latest.processing\_date AND (latest.has\_ongoing\_row = 0 OR raw.\_line >= 0) GROUP BY raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.device, raw.platform\_version, raw.source\_type, raw.page\_type, raw.territory, raw.pre\_order\_start\_date, raw.pre\_order\_end\_date This query names the table as connected without a table name prefix; if you set one, add it wherever the table name appears. | Incremental, Full refresh | processing\_date | app\_id, processing\_date, \_line | | `analytics_app_clip_usage` | How users engage with the app's App Clips, from Apple's App Clip Usage analytics report. Apple restates each report date for about six days, and every restatement is kept as new rows with a later processing\_date, so summing raw rows overcounts. Get one row per report date and dimension combination with: SELECT raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.app\_clip\_event\_type, raw.source\_type, raw.app\_version, raw.device, raw.platform\_version, raw.territory, argMax(raw.counts, raw.processing\_date) AS counts, argMax(raw.total\_session\_duration, raw.processing\_date) AS total\_session\_duration, argMax(raw.unique\_devices, raw.processing\_date) AS unique\_devices FROM appstoreconnect\_analytics\_app\_clip\_usage AS raw INNER JOIN ( SELECT app\_id, date, processing\_date, max(\_line >= 0) AS has\_ongoing\_row FROM appstoreconnect\_analytics\_app\_clip\_usage WHERE (app\_id, date, processing\_date) IN ( SELECT app\_id, date, max(processing\_date) FROM appstoreconnect\_analytics\_app\_clip\_usage GROUP BY app\_id, date ) GROUP BY app\_id, date, processing\_date ) AS latest ON raw.app\_id = latest.app\_id AND raw.date = latest.date AND raw.processing\_date = latest.processing\_date AND (latest.has\_ongoing\_row = 0 OR raw.\_line >= 0) GROUP BY raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.app\_clip\_event\_type, raw.source\_type, raw.app\_version, raw.device, raw.platform\_version, raw.territory This query names the table as connected without a table name prefix; if you set one, add it wherever the table name appears. | Incremental, Full refresh | processing\_date | app\_id, processing\_date, \_line | | `analytics_app_sessions_detailed` | How often people open the app and for how long, with the acquisition attribution columns, from Apple's App Sessions Detailed analytics report. Apple restates each report date for about six days, and every restatement is kept as new rows with a later processing\_date, so summing raw rows overcounts. Get one row per report date and dimension combination with: SELECT raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.app\_version, raw.device, raw.platform\_version, raw.source\_type, raw.page\_type, raw.app\_download\_date, raw.territory, raw.campaign, raw.page\_title, raw.source\_info, argMax(raw.sessions, raw.processing\_date) AS sessions, argMax(raw.total\_session\_duration, raw.processing\_date) AS total\_session\_duration, argMax(raw.unique\_devices, raw.processing\_date) AS unique\_devices FROM appstoreconnect\_analytics\_app\_sessions\_detailed AS raw INNER JOIN ( SELECT app\_id, date, processing\_date, max(\_line >= 0) AS has\_ongoing\_row FROM appstoreconnect\_analytics\_app\_sessions\_detailed WHERE (app\_id, date, processing\_date) IN ( SELECT app\_id, date, max(processing\_date) FROM appstoreconnect\_analytics\_app\_sessions\_detailed GROUP BY app\_id, date ) GROUP BY app\_id, date, processing\_date ) AS latest ON raw.app\_id = latest.app\_id AND raw.date = latest.date AND raw.processing\_date = latest.processing\_date AND (latest.has\_ongoing\_row = 0 OR raw.\_line >= 0) GROUP BY raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.app\_version, raw.device, raw.platform\_version, raw.source\_type, raw.page\_type, raw.app\_download\_date, raw.territory, raw.campaign, raw.page\_title, raw.source\_info This query names the table as connected without a table name prefix; if you set one, add it wherever the table name appears. | Incremental, Full refresh | processing\_date | app\_id, processing\_date, \_line | | `analytics_app_store_downloads_detailed` | How many times people download the app on the App Store, with the acquisition attribution columns, from Apple's App Downloads Detailed analytics report. Apple restates each report date for about six days, and every restatement is kept as new rows with a later processing\_date, so summing raw rows overcounts. Get one row per report date and dimension combination with: SELECT raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.download\_type, raw.app\_version, raw.device, raw.platform\_version, raw.source\_type, raw.page\_type, raw.pre\_order, raw.territory, raw.campaign, raw.page\_title, raw.source\_info, argMax(raw.counts, raw.processing\_date) AS counts FROM appstoreconnect\_analytics\_app\_store\_downloads\_detailed AS raw INNER JOIN ( SELECT app\_id, date, processing\_date, max(\_line >= 0) AS has\_ongoing\_row FROM appstoreconnect\_analytics\_app\_store\_downloads\_detailed WHERE (app\_id, date, processing\_date) IN ( SELECT app\_id, date, max(processing\_date) FROM appstoreconnect\_analytics\_app\_store\_downloads\_detailed GROUP BY app\_id, date ) GROUP BY app\_id, date, processing\_date ) AS latest ON raw.app\_id = latest.app\_id AND raw.date = latest.date AND raw.processing\_date = latest.processing\_date AND (latest.has\_ongoing\_row = 0 OR raw.\_line >= 0) GROUP BY raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.download\_type, raw.app\_version, raw.device, raw.platform\_version, raw.source\_type, raw.page\_type, raw.pre\_order, raw.territory, raw.campaign, raw.page\_title, raw.source\_info This query names the table as connected without a table name prefix; if you set one, add it wherever the table name appears. | Incremental, Full refresh | processing\_date | app\_id, processing\_date, \_line | | `analytics_installations_deletions_detailed` | How many times users install and delete the app, with the acquisition attribution columns, from Apple's App Store Installation and Deletion Detailed analytics report. Apple restates each report date for about six days, and every restatement is kept as new rows with a later processing\_date, so summing raw rows overcounts. Get one row per report date and dimension combination with: SELECT raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.event, raw.download\_type, raw.app\_version, raw.device, raw.platform\_version, raw.source\_type, raw.page\_type, raw.app\_download\_date, raw.territory, raw.campaign, raw.page\_title, raw.source\_info, argMax(raw.counts, raw.processing\_date) AS counts, argMax(raw.unique\_devices, raw.processing\_date) AS unique\_devices FROM appstoreconnect\_analytics\_installations\_deletions\_detailed AS raw INNER JOIN ( SELECT app\_id, date, processing\_date, max(\_line >= 0) AS has\_ongoing\_row FROM appstoreconnect\_analytics\_installations\_deletions\_detailed WHERE (app\_id, date, processing\_date) IN ( SELECT app\_id, date, max(processing\_date) FROM appstoreconnect\_analytics\_installations\_deletions\_detailed GROUP BY app\_id, date ) GROUP BY app\_id, date, processing\_date ) AS latest ON raw.app\_id = latest.app\_id AND raw.date = latest.date AND raw.processing\_date = latest.processing\_date AND (latest.has\_ongoing\_row = 0 OR raw.\_line >= 0) GROUP BY raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.event, raw.download\_type, raw.app\_version, raw.device, raw.platform\_version, raw.source\_type, raw.page\_type, raw.app\_download\_date, raw.territory, raw.campaign, raw.page\_title, raw.source\_info This query names the table as connected without a table name prefix; if you set one, add it wherever the table name appears. | Incremental, Full refresh | processing\_date | app\_id, processing\_date, \_line | | `analytics_discovery_engagement_detailed` | How users find and interact with the app on the App Store, with the acquisition attribution columns, from Apple's App Store Discovery and Engagement Detailed analytics report. Apple restates each report date for about six days, and every restatement is kept as new rows with a later processing\_date, so summing raw rows overcounts. Get one row per report date and dimension combination with: SELECT raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.event, raw.page\_type, raw.source\_type, raw.engagement\_type, raw.device, raw.platform\_version, raw.territory, raw.campaign, raw.page\_title, raw.source\_info, argMax(raw.counts, raw.processing\_date) AS counts, argMax(raw.unique\_counts, raw.processing\_date) AS unique\_counts FROM appstoreconnect\_analytics\_discovery\_engagement\_detailed AS raw INNER JOIN ( SELECT app\_id, date, processing\_date, max(\_line >= 0) AS has\_ongoing\_row FROM appstoreconnect\_analytics\_discovery\_engagement\_detailed WHERE (app\_id, date, processing\_date) IN ( SELECT app\_id, date, max(processing\_date) FROM appstoreconnect\_analytics\_discovery\_engagement\_detailed GROUP BY app\_id, date ) GROUP BY app\_id, date, processing\_date ) AS latest ON raw.app\_id = latest.app\_id AND raw.date = latest.date AND raw.processing\_date = latest.processing\_date AND (latest.has\_ongoing\_row = 0 OR raw.\_line >= 0) GROUP BY raw.date, raw.app\_id, raw.app\_name, raw.app\_apple\_identifier, raw.event, raw.page\_type, raw.source\_type, raw.engagement\_type, raw.device, raw.platform\_version, raw.territory, raw.campaign, raw.page\_title, raw.source\_info This query names the table as connected without a table name prefix; if you set one, add it wherever the table name appears. | Incremental, Full refresh | processing\_date | app\_id, processing\_date, \_line | ## Troubleshooting - If the connection fails with an authorization error, the private key (.p8 contents) is wrong, expired, or has been revoked. Create a new one, then reconnect the source. - If a table syncs no rows, the credential may not have access to that data. Check its permissions, then reconnect the source. If your sync is failing or data looks wrong, see the [Data warehouse troubleshooting guide](https://posthog.com/docs/data-warehouse/troubleshooting.md). If that doesn't help, [contact support](https://us.posthog.com/#panel=support%3Asupport%3Adata_warehouse%3A%3Atrue) – we're happy to help.