Netice app revenue data infrastructure
BigQuery warehouse refresh and merge behavior for app revenue
Netice updates managed BigQuery app revenue tables through staged loads, selected-window refreshes, schema checks and duplicate safeguards. The goal is to keep app revenue data queryable in the customer’s warehouse without blind duplicate appends, unsafe full-table rewrites or confusion between daily analytics and monthly finance output.
What this BigQuery refresh behavior is for
This page explains how Netice approaches managed BigQuery output for app revenue data. It is written for data engineers, analytics engineers, finance operations teams and technical buyers who need to know what happens when a first run, recurring refresh, rerun or backfill updates a BigQuery app revenue table.
The main daily app-sales table is app_sales_daily. It is produced by the Daily App Sales workflow and is designed for operational analytics over Apple App Store and Google Play daily app-sales reporting. It is not a raw report landing table and not a monthly finance table.
The monthly finance table, where Finance Unified is configured, is finance_unified. It uses finance-period semantics rather than daily revenue_date semantics. These two BigQuery outputs should remain separate in destination naming, refresh behavior and downstream models.
The customer-facing model
Netice does not treat every app revenue run as a new public BigQuery table. The safer customer-facing model is a stable managed table that Netice refreshes by selected reporting windows or finance periods.
For daily app sales, that means selected daily windows can be refreshed in app_sales_daily. For Finance Unified, monthly finance periods can be refreshed in finance_unified. For provider-native raw reports, current public-facing evidence should point customers to GCS/S3 raw object output unless raw warehouse loading is explicitly enabled and approved for publication.
Managed BigQuery table model
A managed BigQuery table is the table Netice keeps current for a configured app revenue task. The table should be stable enough for downstream SQL, BI models and scheduled dashboards to depend on it, while still allowing recent provider windows to be refreshed when data arrives late or changes.
| Output family | Default BigQuery table | Refresh scope | Use |
|---|---|---|---|
| Daily App Sales | app_sales_daily |
Daily reporting windows by date and source context. | Operational daily app-sales analytics. |
| Finance Unified | finance_unified |
Monthly/fiscal finance periods and finance source scope. | Monthly platform finance review where configured. |
| Raw Reports | Not public-default raw BigQuery loading. | Gated/not public-default in current evidence. | Use GCS/S3 for provider-native raw report custody unless product approves raw warehouse rollout. |
Daily app-sales BigQuery refresh
The daily app-sales BigQuery path is designed around app_sales_daily. It receives enriched daily rows from app store sales-style reporting. The table includes source and report-family context such as source, platform, source_kind and source_report, so Apple and Google rows can coexist without losing their source meaning.
A refresh does not need to mean “append everything again.” Netice stages candidate rows, checks the candidate output and refreshes the selected window in the managed table. This is important because app stores can publish late data, update recent reports or produce empty windows that should not automatically erase existing data.
| Refresh concept | What Netice is designed to do | Unsafe assumption to avoid |
|---|---|---|
| Staged candidate data | Prepare candidate rows before treating them as usable table output. | Rows are blindly appended without checks. |
| Selected-window refresh | Refresh a bounded reporting window in the managed table. | The whole table is dropped, truncated or deleted by default. |
| Source-aware rows | Keep provider and source report fields visible. | Apple and Google rows become anonymous revenue rows. |
| Stable table | Keep app_sales_daily as the customer-facing table. |
Every rerun creates a new public table. |
What gets staged before a refresh
In a safe warehouse workflow, candidate rows are prepared before the final managed table is updated. That staging step gives Netice a place to validate candidate data shape, source context, type compatibility and duplicate behavior.
BigQuery setup for daily app sales can require a GCS staging bucket. That staging bucket is part of the BigQuery loading process. It is not the same thing as a customer-facing GCS file export. Public documentation should therefore avoid showing staging object names, job IDs or internal table names.
| Setup item | Purpose | Public example |
|---|---|---|
| Google/Apple source access | Read selected app store reports. | example_google_play_reporting |
| BigQuery destination access | Write the managed table. | example_bigquery_app_revenue |
| BigQuery table | Customer-owned managed output table. | example_project.example_dataset.app_sales_daily |
| GCS staging bucket | Warehouse loading support for BigQuery. | example_bucket |
Window-scoped daily refresh
Daily App Sales uses daily reporting windows. A first run, backfill or recurring refresh may target a selected date range. The output should be interpreted as a refresh of that selected app-sales window, not as a blind full-table rewrite.
The current validation evidence supports a recurring daily refresh model for recent completed days, with a default recent-window behavior and a configured cap. That is useful because provider data can arrive late or stabilize after the first time a day is processed.
| Run type | Daily BigQuery behavior | Boundary |
|---|---|---|
| First run | Creates or populates the managed table for the selected setup scope. | Do not describe as synchronous browser work. |
| Recurring refresh | Refreshes recent completed daily windows. | Do not claim user-selected exact provider clock time. |
| Manual backfill or rerun | Rebuilds a bounded selected window. | Do not claim unlimited history or immediate completion. |
| Provider follow-up | Can re-check provider-late windows. | Do not treat provider-late data as customer error. |
Empty candidate and provider-late handling
Empty candidate data is a special case. A provider can have no rows for a window because data is late, unavailable, filtered out, not generated yet or affected by source access. A safe BigQuery refresh should not automatically interpret an empty candidate as permission to delete the existing target window.
The public wording should be simple: Netice uses guards so an empty candidate window is not treated as a normal replacement of existing warehouse data. This is not a customer-visible restore guarantee or an SLA; it is a safety boundary for managed output behavior.
| Condition | Safe interpretation | Wrong interpretation |
|---|---|---|
| Provider has no rows for the requested date. | Investigate provider readiness or source availability. | Assume revenue was exactly zero. |
| Candidate stage is empty. | Guard the managed table from unsafe replacement. | Delete the prior target window. |
| Provider data arrives late. | Refresh the affected recent window later. | Treat the original run as permanent finance truth. |
Duplicate and schema checks
Managed warehouse output needs quality checks. BigQuery app revenue rows are not useful if duplicate candidate rows, incompatible table types or invalid casts silently flow into the final table.
Netice’s public article should describe the high-level controls: staged candidate validation, duplicate checks, typed table behavior and schema/type compatibility checks. It should not publish internal SQL scripts or implementation-specific merge logic.
| Check | Why it matters | Public-safe wording |
|---|---|---|
| Stage duplicate check | Prevents ambiguous candidate rows from becoming managed output. | Bad candidate rows can block output. |
| Target duplicate check | Detects unexpected duplicate state after the managed update. | Post-refresh validation can surface duplicate problems. |
| Typed table check | Keeps enriched warehouse output from becoming a raw string dump. | Daily app-sales BigQuery output is typed enriched data. |
| Schema/type conflict | Prevents incompatible existing tables from being silently overwritten. | Table conflicts may require review or migration. |
Source access vs destination access
A BigQuery refresh can fail because of source access, destination access, provider availability or warehouse schema issues. These are different categories and should not be collapsed into “the run failed.”
Google Play or Apple App Store source access lets Netice read provider reports. BigQuery destination access lets Netice write the customer-owned warehouse table and use the configured staging path. Fixing one side does not automatically fix the other.
| Failure category | What it means | What not to expose |
|---|---|---|
| Source access failure | Netice cannot read the selected app store report family. | Provider credential payloads or raw source errors. |
| Destination permission failure | Netice cannot write or verify the BigQuery/GCS destination target. | Real project IDs, buckets, object paths or service-account JSON. |
| Provider-late data | Provider report data is not ready yet or arrives later. | Do not call it customer error by default. |
| Schema conflict | Existing table shape or candidate values need review. | Internal SQL, staging objects, logs or stack traces. |
Finance Unified BigQuery contrast
Finance Unified BigQuery behavior is relevant as a contrast, not as a substitute for daily app-sales refresh. The daily table app_sales_daily uses daily app-sales windows. Finance Unified uses finance_unified and finance-period replacement scope.
Finance rows use source_kind = 'FINANCE'. They come from monthly platform finance report families such as Apple financeReports and Google Play Earnings where configured. They should not be inserted into app_sales_daily, and daily rows should not be used as if they were monthly finance rows.
| Question | Daily App Sales BigQuery | Finance Unified BigQuery |
|---|---|---|
| Default table | app_sales_daily |
finance_unified |
| Source kind | SALES |
FINANCE |
| Refresh scope | Daily reporting windows. | Finance periods and finance source scope. |
| Best use | Daily operational analytics. | Monthly platform finance review. |
| Wrong use | Accounting close or payout reconciliation. | Daily product analytics replacement. |
Raw report BigQuery caveat
Raw reports are provider-native artifacts. Current public-facing evidence should not advertise raw BigQuery loading as generally available or public-default. Raw report warehouse code paths may exist behind gates, but the safe public statement is that provider-native raw reports should be planned around GCS/S3 unless product explicitly enables and approves raw warehouse documentation.
This distinction matters because raw reports, daily enriched app-sales rows and Finance Unified rows have different schemas and meanings. A raw Google Play file is not automatically the app_sales_daily table. A raw Apple finance report file is not automatically a finance_unified row.
Safe synthetic examples
The examples below are synthetic. They are intended to show safe mental models and query shapes without exposing real project IDs, datasets, tables, staging paths, job IDs, task IDs, run IDs, logs, source rows, app IDs, SKUs, source row hashes, credentials or customer data.
Managed BigQuery targets
Daily App Sales table: example_project.example_dataset.app_sales_daily
Finance Unified table: example_project.example_dataset.finance_unified
Daily refresh mental model
Requested window: 2026-02-01 through 2026-02-07
Candidate rows: staged and checked before managed table update
Target update: selected daily window only
Stable table: example_project.example_dataset.app_sales_daily
Daily app-sales query
SELECT
revenue_date,
platform,
source_report,
COUNT(*) AS rows
FROM `example_project.example_dataset.app_sales_daily`
WHERE revenue_date BETWEEN DATE '2026-02-01' AND DATE '2026-02-07'
GROUP BY revenue_date, platform, source_report
ORDER BY revenue_date, platform, source_report;
Finance contrast query
SELECT
fiscal_period,
source_report,
COUNT(*) AS rows
FROM `example_project.example_dataset.finance_unified`
WHERE fiscal_period = DATE '2026-02-01'
GROUP BY fiscal_period, source_report
ORDER BY fiscal_period, source_report;
The first query is daily operational analytics. The second query shows finance-period shape. Neither query is payout reconciliation, accounting close, audit evidence or an internal Netice merge script.
FAQ
Does Netice append duplicate rows to BigQuery?
Netice is designed around managed table refresh behavior, not blind duplicate appends. Candidate rows can be staged and checked before selected windows are refreshed in the managed table.
What is the default BigQuery table for daily app sales?
The current default daily app-sales BigQuery table is app_sales_daily. Public examples should use synthetic full names such as example_project.example_dataset.app_sales_daily.
Why does BigQuery setup need a GCS staging bucket?
The GCS staging bucket supports the BigQuery load process. It is not the same as customer-facing GCS file export output.
Does a rerun create a new BigQuery table?
The customer-facing model is a stable managed table. A rerun or backfill should refresh a selected window rather than create a new public table by default.
What happens if a provider has no rows for a requested window?
Empty candidate data is handled as a special condition. It should not automatically erase existing warehouse data or be interpreted as zero revenue without context.
How are backfills different from recurring refreshes?
A backfill is a selected historical window. A recurring refresh updates recent configured windows. Both should remain bounded rather than being described as unlimited warehouse rebuilds.
Is app_sales_daily the same as Finance Unified?
No. app_sales_daily is the daily app-sales table. Finance Unified uses the separate finance_unified table and finance-period semantics.
Are raw App Store or Google Play reports loaded to BigQuery?
Current public-facing evidence should not advertise raw BigQuery loading as generally available. Raw reports should be treated as provider-native files for GCS/S3 unless product approves raw warehouse rollout language.
Can this BigQuery table be used for payout reconciliation?
Daily App Sales BigQuery output is operational analytics. It is not payout reconciliation, final settlement, accounting close, audited revenue, GAAP, IFRS, ASC 606 or bank reconciliation truth.
What should I check if BigQuery refresh fails?
Check the failure category: source access, destination permission, provider readiness, schema/type conflict, duplicate candidate rows or other safe diagnostic state. Do not expose raw logs or credentials in public examples.
Related guides
- Product overview
- Product documentation
- App revenue to BigQuery
- Google Play revenue to BigQuery
- App Store Connect reports to BigQuery
- Unified daily app sales schema
- App revenue backfills and reruns
- Daily app sales vs platform finance reports
- Monthly platform finance schema
- Finance Unified monthly platform finance
- Saved connections for app revenue pipelines
- Security policy
- Pricing
Keep app revenue BigQuery tables stable and source-aware
Netice helps app teams keep managed BigQuery app revenue tables current through staged loads, selected-window refreshes, source-aware rows and clear boundaries between daily analytics, finance output and raw report custody.