Google Search Console setup
This runbook verifies a domain with a DNS TXT record, adds it to Google Search Console as a Domain property and
connects it to a brand in BoostUp. It follows the setup we ran for boostup.cloud (Cloudflare DNS) on 2026-11-12,
including the two errors we hit and how we got past them.
Result for boostup.cloud: the property sc-domain:boostup.cloud, permission level siteOwner.
Before you start
You need:
- A Google account that will own the property (use a shared company account, not a personal one).
- A Google Cloud project with an OAuth client, if you use the API or connect the property to BoostUp.
- Access to the domain's DNS (for us, the Cloudflare dashboard).
OAuth scopes
| Scope | Needed for |
|---|---|
https://www.googleapis.com/auth/webmasters.readonly | BoostUp reading Search Console data. The only Search Console scope the token you give BoostUp needs. |
https://www.googleapis.com/auth/siteverification | Setup only: asking for a verification token and verifying the domain. |
https://www.googleapis.com/auth/webmasters | Setup only: adding the property (sites.add). |
Do the setup with a token that has the setup scopes, then mint a separate read-only refresh token for BoostUp. BoostUp never needs write access to Search Console.
1. Enable the APIs in Google Cloud Console
In Google Cloud Console, pick the project that owns your OAuth client, open APIs and services, then Library, and enable:
- Google Search Console API
- Site Verification API
What went wrong. Our first call for a verification token returned 403:
Site Verification API has not been used in project <project number> before or it is disabled. Enable it by
visiting https://console.developers.google.com/apis/api/siteverification.googleapis.com/overview?project=<project number>
then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
Fix. We enabled Site Verification API in the Library and retried about six minutes later; it worked. If it still fails right after enabling, wait a few minutes: the change takes time to propagate.
2. Create the OAuth client and a refresh token
In Google Cloud Console open Google Auth Platform:
- Branding: set the app name and support contact.
- Audience: add the owner account as a test user, or publish the app. While the app is in Testing, Google expires refresh tokens after 7 days, which breaks BoostUp's daily sync.
- Clients: Create client, type Desktop app (or Web application with your redirect URI). Keep the client id and client secret in your password manager, never in the repository.
Run the OAuth consent flow with access_type=offline and prompt=consent so Google returns a refresh_token.
3. Ask Google for the DNS verification token
By hand: in Search Console, Add property, choose Domain, enter
boostup.cloud and copy the TXT record Google shows you.
By API:
POST https://www.googleapis.com/siteVerification/v1/token
Content-Type: application/json
{
"site": { "type": "INET_DOMAIN", "identifier": "boostup.cloud" },
"verificationMethod": "DNS_TXT"
}
Returned 200:
{ "method": "DNS_TXT", "token": "google-site-verification=<redacted>" }
4. Add the TXT record in Cloudflare
In the Cloudflare dashboard, open the domain, then DNS, then Records, and Add record:
| Field | Value |
|---|---|
| Type | TXT |
| Name | @ (the apex, boostup.cloud) |
| Content | the whole token, starting with google-site-verification= |
| TTL | Auto |
Save. Keep the record forever: Google checks it again later, and removing it can unverify the domain.
Check that public resolvers see it before you verify:
dig +short TXT boostup.cloud @1.1.1.1
dig +short TXT boostup.cloud @8.8.8.8
5. Verify the domain
By hand: click Verify in the Search Console dialog.
By API:
POST https://www.googleapis.com/siteVerification/v1/webResource?verificationMethod=DNS_TXT
Content-Type: application/json
{ "site": { "type": "INET_DOMAIN", "identifier": "boostup.cloud" } }
What went wrong. The first attempt, 3 seconds after the record was created, returned 400:
The necessary verification token could not be found on your site.
Fix. DNS had not propagated yet. The same request succeeded about 20 seconds later and returned 200:
{
"id": "dns%3A%2F%2Fboostup.cloud",
"site": { "type": "INET_DOMAIN", "identifier": "boostup.cloud" },
"owners": ["<owner email>"]
}
Automations should retry this call with a backoff (for example 10, 20, 40 seconds, then a few minutes) instead of
failing on the first 400.
6. Add the property to Search Console
Verification alone does not add the property to your Search Console list. If you verified by API, add it:
PUT https://www.googleapis.com/webmasters/v3/sites/sc-domain%3Aboostup.cloud
Returned 204 with an empty body. Then list your properties to confirm:
GET https://www.googleapis.com/webmasters/v3/sites
Returned 200:
{
"siteEntry": [
{ "siteUrl": "sc-domain:boostup.cloud", "permissionLevel": "siteOwner" },
{ "siteUrl": "sc-domain:prolevelsolutions.com", "permissionLevel": "siteOwner" }
]
}
The siteUrl is the value BoostUp needs. A Domain property is always sc-domain: followed by the bare domain; a
URL-prefix property is the full URL with a trailing slash, for example https://www.example.com/.
7. Check that data comes back
Search Console data arrives with a delay of about 2 to 3 days, and a new property is empty until then. To test
the token and the query shape, query a property that already has data. We used prolevelsolutions.com on
2026-11-12, ending the range two days earlier:
POST https://www.googleapis.com/webmasters/v3/sites/sc-domain%3Aprolevelsolutions.com/searchAnalytics/query
Content-Type: application/json
{ "startDate": "2026-10-14", "endDate": "2026-11-10", "dimensions": ["query"], "rowLimit": 8 }
Returned 200 with 8 rows, each with keys, clicks, impressions, ctr and position, and
"responseAggregationType": "byProperty". One row:
{ "keys": ["pro level"], "clicks": 0, "impressions": 22, "ctr": 0, "position": 9.95 }
Always end date ranges at least two days before today, or the last days will look like a traffic drop.
8. Connect the property to a brand in BoostUp
A platform admin imports the Google credentials for a brand with POST /admin/integrations/import-google. The same
call carries the GA4 property, so you can do this once after the GA4 setup.
{
"org_id": "<organization id>",
"brand_id": "<brand id>",
"token": {
"client_id": "<OAuth client id>",
"client_secret": "<OAuth client secret>",
"refresh_token": "<refresh token with webmasters.readonly and analytics.readonly>"
},
"gsc_site_url": "sc-domain:boostup.cloud",
"ga4_property_id": "properties/563971554"
}
gsc_site_urlis thesiteUrlfrom step 6, for examplesc-domain:example.com.ga4_property_idacceptsproperties/524312236or just524312236.- Like every mutation, the call needs a signed-in admin session and the
X-CSRF-Tokenheader (see the API overview). - The token JSON is a secret. Send it only to this endpoint over HTTPS. Never paste it in a ticket, a chat or the repository.