Skip to content
Patronage Ads Sync Docs
Esc
navigateopen⌘Jpreview
On this page

Google Search Console caveats

What to expect from Google OAuth Testing mode, the seam's cold-start retry, final versus provisional data, and the two auth modes of the Search Console image.

Google Search Console is the Supported Provider the quickstart uses. It has four properties that surprise a first-time operator. None of them is a bug in your deployment.

the Testing-mode refresh token expires after seven days

A Google Cloud OAuth consent screen starts in Testing publishing status. In that status Google issues refresh tokens that expire after seven days. The token then stops working with invalid_grant, every scheduled tick fails at the connector’s check, and the watermark stays where it was.

For a quickstart that is fine: create the token, run the tutorial, tear down. For a deployment that runs longer than a week, you need one of these:

  • Publish the app. The webmasters.readonly scope is a sensitive scope, so publishing to In production requires Google’s app verification. Verified apps get refresh tokens that do not expire on a timer. Plan for that review before you rely on the Cron trigger.
  • Rotate the token every seven days. Repeat the browser consent and the curl exchange from the quickstart, then run wrangler secret put GOOGLE_SEARCH_CONSOLE_SOURCE_CONFIG_JSON again. Each secret put publishes a new Worker version; the next tick reads the new token. Nothing in Postgres or R2 changes, because the deployment never stores the token.

Google Workspace accounts can also use an Internal consent screen, which does not carry the seven-day limit and needs no verification. That option is only available when the property owner is a Workspace user.

Either way, the token is yours. Single-tenant custody (ADR 0047) means the refresh token lives only in your Worker secrets or your local Wrangler dev vars file. Do not paste it into wrangler.jsonc, ads-sync.config.ts, or a chat.

the cold-start retry is seam behavior

The first request to a new Cloudflare Container instance can fail while the instance starts. The wrapper’s GET /metadata answers late or with a transient error, and a naive caller marks a valid run failed before Airbyte even ran.

The Qualified Run seam owns this. assertContainerImagePin retries only an unavailable Container, up to five attempts two seconds apart (DEFAULT_COLD_START_RETRY), and then reads connectorImage and wrapperVersion from /metadata and compares them with the exact pin. A Container that answers with the wrong image or wrapper version fails at once with metadata_mismatch; that is never retried.

You do not configure this. Do not add your own retry loop around POST /runs, and do not treat one container did not respond to /metadata after 5 attempt(s) as a credential problem. That message means the Container never became reachable: the class is not enabled in wrangler.jsonc, the image did not build, or the account is not on Workers Paid.

final data lags by three days

Search Console finalizes query and page rows two to three days after the fact. The Reference Deployment reads to the Final-Data Horizon: UTC midnight three days before the tick date (DEFAULT_FINAL_DATA_LAG_DAYS.google_search_console). A tick before the horizon moves records no_new_final_data and starts no Containers.

Provisional rows exist and are sometimes useful, but they change. Reading them is an explicit, audited mode: set the SCHEDULE_PROVISIONAL_READS var to the literal "true". Run rows then carry trigger_type = cron_provisional or manual_provisional, and the tick ledger records read_mode = provisional. The default is final-data reads; keep it unless you know why you need otherwise.

The Historical Comparison Gate applies the same discipline: a Google Search Console comparison window must end at least seven days before stableAsOf.

the image has two auth modes

The pinned Search Console connector advertises access_token in its spec but selects refresh-token OAuth unconditionally in its manifest. The shipped Dockerfile.gsc therefore takes a build argument:

GSC_AUTH_MODE who uses it what the image expects
refresh_token (default) Single-tenant operators, including the quickstart authorization.client_id, client_secret, and refresh_token in the source config, exactly as Google issued them.
access_token Deployments that exchange a refresh token for a short-lived access token before dispatch authorization.access_token only. googleSearchConsoleAccessTokenSourceConfig() builds that config. The exact-match patch patch-gsc-manifest-auth.py rewrites the manifest authenticator; the build fails when the pinned upstream text does not match.

The Reference Deployment builds the default. Do not switch modes without rebuilding and redeploying the image; /metadata reports the selected mode as buildOptions.

Was this page helpful?