Skip to main content
RapidDev - Software Development Agency
bubble-integrationsBubble API Connector

Google Search Console

Connect Bubble to Google Search Console by using the API Connector in a two-call chain: first exchange a Google OAuth2 refresh_token for a short-lived access_token, then POST to the Search Analytics API to query clicks, impressions, CTR, and position data. Because Bubble cannot sign RSA JWTs natively, the refresh_token path (generated via Google's OAuth Playground) is the practical workaround — all credentials stay Private in the API Connector and the integration runs entirely server-side.

What you'll learn

  • Why Bubble cannot use the standard Google service account JWT flow and how the refresh_token workaround solves this
  • How to generate a long-lived offline refresh_token via the Google OAuth 2.0 Playground for the Search Analytics API scope
  • How to configure a two-call API Connector chain for token refresh and Search Analytics queries in Bubble
  • How to structure the Search Analytics API query body with dimensions, date ranges, and row limits
  • Why the siteUrl in the API path must exactly match your GSC property URL (including trailing slash)
  • How to handle the 2–3 day GSC data processing lag so you never show misleading recent data
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Advanced20 min read3–4 hoursAnalyticsLast updated July 2026RapidDev Engineering Team
TL;DR

Connect Bubble to Google Search Console by using the API Connector in a two-call chain: first exchange a Google OAuth2 refresh_token for a short-lived access_token, then POST to the Search Analytics API to query clicks, impressions, CTR, and position data. Because Bubble cannot sign RSA JWTs natively, the refresh_token path (generated via Google's OAuth Playground) is the practical workaround — all credentials stay Private in the API Connector and the integration runs entirely server-side.

Quick facts about this guide
FactValue
ToolGoogle Search Console
CategoryAnalytics
MethodBubble API Connector
DifficultyAdvanced
Time required3–4 hours
Last updatedJuly 2026

Building a GSC Search Analytics Dashboard Inside Bubble

Google Search Console's Search Analytics API lets you query organic search performance data — which queries bring traffic, which pages rank for them, CTR, impressions, and average position — and display it inside any application. For SEO teams and agencies using Bubble to build internal reporting tools or client portals, this integration surfaces the same data as the GSC UI directly inside a Bubble dashboard.

The core technical challenge in Bubble is authentication. The GSC Search Analytics API requires OAuth2 with a Google account that has access to the GSC property. Google's standard server-to-server authentication uses a service account JSON key with RSA private key signing — a process Bubble's API Connector cannot do natively. Instead of the JWT-signing flow, this tutorial uses the OAuth 2.0 refresh_token approach: a long-lived token you generate once using the Google OAuth Playground and store securely in Bubble's API Connector as a Private parameter. Bubble exchanges this token for a short-lived access_token (valid 1 hour) on each use.

Two important limitations to set expectations correctly: - This integration requires a paid Bubble plan for scheduled Backend Workflow token refresh (otherwise, access_tokens expire after 1 hour with no auto-renewal). - GSC data has a 2–3 day processing lag. Do not use 'today' or 'yesterday' as the query end date — these dates return zero or incomplete data. Use date ranges ending at least 3 days ago.

Integration method

Bubble API Connector

Bubble's API Connector chains two server-side calls: a token refresh call (client_secret + refresh_token marked Private) and a Search Analytics API query — all without RSA JWT signing.

Prerequisites

  • A Google Search Console property that you have at least Viewer (read) access to — full ownership is not required but the account generating the refresh_token must have access
  • A Google Cloud project with the Google Search Console API enabled (console.cloud.google.com → APIs & Services → Library → search 'Google Search Console API')
  • OAuth 2.0 Client credentials created in your Google Cloud project (a Web application or Desktop app client_id and client_secret — used in the OAuth Playground)
  • The API Connector plugin installed in your Bubble app (Plugins tab → Add plugins → search 'API Connector' by Bubble → Install)
  • A paid Bubble plan if you want automatic token refresh every hour via a Backend Workflow scheduler

Step-by-step guide

1

Enable the Search Console API and Create Google Cloud OAuth Credentials

Start in the Google Cloud Console (console.cloud.google.com). Select or create a project dedicated to this integration. Go to APIs & Services → Library. Search for 'Google Search Console API' and click Enable. This is the API that powers the Search Analytics query endpoint. Next, go to APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client IDs. Choose application type 'Web application' (this gives you a client_id and client_secret that work with the OAuth Playground). Name it 'Bubble GSC Integration'. In the 'Authorized redirect URIs' section, add: https://developers.google.com/oauthplayground This URI is required so the OAuth Playground can receive the authorization code and exchange it for tokens. Click Create. Copy both the Client ID and the Client Secret. You will need them in the next step when you set up the OAuth Playground, and later when you configure the Bubble API Connector. Also note your GSC property URL at this point — go to Google Search Console and click your property to find its exact URL. Properties come in two formats: - URL prefix format: https://www.example.com/ (note the trailing slash) - Domain format: sc-domain:example.com The exact property URL (including the trailing slash for URL prefix properties) is used as a path parameter in the Search Analytics API. A single character difference produces a 403 error even with correct OAuth credentials — so note the exact format now.

gsc_google_cloud_setup.json
1{
2 "google_cloud_setup": {
3 "step1": "console.cloud.google.com → APIs & Services → Library → search 'Google Search Console API' → Enable",
4 "step2": "APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client IDs → Web application",
5 "step3": "Add authorized redirect URI: https://developers.google.com/oauthplayground",
6 "step4": "Copy: client_id and client_secret"
7 },
8 "gsc_property_url_formats": {
9 "url_prefix": "https://www.example.com/",
10 "domain": "sc-domain:example.com",
11 "note": "URL-encode when used in the API path: https%3A%2F%2Fwww.example.com%2F"
12 }
13}

Pro tip: Use a Google Cloud project specifically for this integration (not your personal or main project) so it is easy to manage API quotas and revoke access if needed. Give it a clear name like 'Bubble-GSC-Integration'.

Expected result: A Google Cloud OAuth 2.0 Client ID and Client Secret copied and ready to use, with the Google Search Console API enabled in the project and the OAuth Playground added as an authorized redirect URI.

2

Generate a Long-Lived Offline Refresh Token via the OAuth Playground

The OAuth 2.0 Playground (https://developers.google.com/oauthplayground) lets you generate the OAuth tokens needed for the Bubble integration without writing any code. This is how you get around Bubble's inability to sign RSA JWTs. Open the OAuth Playground in your browser. Click the gear icon at the top right → Settings. Check 'Use your own OAuth credentials'. Enter your Google Cloud Client ID and Client Secret from the previous step. Close settings. In Step 1 (Select & authorize APIs), find 'Google Search Console API v3' in the list and expand it. Check the scope 'https://www.googleapis.com/auth/webmasters.readonly' (read-only access to Search Console data — sufficient for querying the Search Analytics API). Click 'Authorize APIs'. Google will ask you to sign in and grant access. Sign in with the Google account that has access to the GSC property you want to query. On the consent screen, click Allow. You will be redirected back to the OAuth Playground with an authorization code. In Step 2 (Exchange authorization code for tokens), click 'Exchange authorization code for tokens'. The Playground shows the response containing: - access_token (short-lived, expires in 3600 seconds) - refresh_token (long-lived, use this in Bubble) - token_type: Bearer Copy the refresh_token value. This is the credential that Bubble will use to obtain fresh access_tokens. Treat it like a password — it grants read access to your GSC data. Note: the access_token shown here expires quickly. Do not store it — Bubble will generate fresh ones via the token refresh call.

oauth_playground_steps.json
1{
2 "oauth_playground_steps": {
3 "url": "https://developers.google.com/oauthplayground",
4 "step1": "Settings (gear) → Use your own OAuth credentials → enter client_id + client_secret",
5 "step2": "Select scope: https://www.googleapis.com/auth/webmasters.readonly",
6 "step3": "Authorize APIs → sign in with GSC property owner account → Allow",
7 "step4": "Exchange authorization code for tokens → copy refresh_token"
8 },
9 "credentials_for_bubble": {
10 "client_id": "[from Google Cloud Console]",
11 "client_secret": "[from Google Cloud Console — PRIVATE]",
12 "refresh_token": "[from OAuth Playground response — PRIVATE]"
13 }
14}

Pro tip: Refresh tokens generated with 'External' OAuth consent screen status can expire after 7 days if the project is in 'Testing' mode. To get a non-expiring refresh_token, publish your OAuth consent screen to 'Production' status in Google Cloud Console → APIs & Services → OAuth consent screen, or use an Internal consent screen (requires Google Workspace). For agency use, ensure you generate the refresh_token with the specific client account that owns the GSC property.

Expected result: A long-lived refresh_token copied and stored securely, along with your client_id and client_secret. These three values are all you need to configure the Bubble API Connector.

3

Configure API Connector Call 1: Token Refresh

In your Bubble app, click the Plugins tab → API Connector. If it is not already installed, click 'Add plugins', search for 'API Connector' (by Bubble), and install it. Click 'Add another API'. Name this group 'Google OAuth'. Leave the base URL empty (the full URL goes in the call). Click 'Add another call'. Name it 'Refresh Access Token'. Method: POST. URL: https://oauth2.googleapis.com/token. Set the body type to 'Form data'. Add four parameters: - client_id: your Google Cloud client ID. Private: UNCHECKED (this is a public identifier). - client_secret: your Google Cloud client secret. Private: CHECKED — this is sensitive and must never appear in Bubble's logs. - refresh_token: the long-lived token from the OAuth Playground. Private: CHECKED — treat this like a password. - grant_type: the fixed string 'refresh_token'. Private: UNCHECKED. Set 'Use as' to 'Action'. Click 'Initialize call'. Bubble sends the POST request to Google. A successful response looks like: {"access_token": "ya29.a0...", "expires_in": 3599, "token_type": "Bearer", "scope": "https://www.googleapis.com/auth/webmasters.readonly"} If you see 'There was an issue setting up your call' or the Initialize fails: - Check that the body type is Form data (not JSON) - Verify the refresh_token is not expired or revoked (if so, regenerate it in the OAuth Playground) - Confirm the Google Search Console API is enabled in your Google Cloud project - Verify the client_id and client_secret match the credentials used to generate the refresh_token in the same Google Cloud project

gsc_token_refresh_call.json
1{
2 "method": "POST",
3 "url": "https://oauth2.googleapis.com/token",
4 "body_type": "form_data",
5 "body_params": {
6 "client_id": "{{client_id}}",
7 "client_secret": "<private>",
8 "refresh_token": "<private>",
9 "grant_type": "refresh_token"
10 },
11 "use_as": "Action",
12 "expected_success_response": {
13 "access_token": "ya29.a0...",
14 "expires_in": 3599,
15 "token_type": "Bearer"
16 }
17}

Pro tip: The access_token returned here is valid for 3599 seconds (just under 1 hour). Store the expiry time in the Bubble database as 'Current date/time + 3540 seconds' to give yourself a safe buffer before triggering a refresh.

Expected result: A successful Initialize response with an access_token. The 'Refresh Access Token' call appears as an Action in Bubble Workflows, ready to be chained before any Search Analytics API call.

4

Configure API Connector Call 2: Search Analytics Query

Click 'Add another API' in the API Connector. Name this group 'Google Search Console API'. Set the base URL to: https://searchconsole.googleapis.com/webmasters/v3 Add a shared header to this group: Key = Authorization, Value = Bearer [leave empty — populated dynamically from Workflow], Private = CHECKED. Click 'Add another call'. Name it 'Query Search Analytics'. Method: POST. Endpoint path: /sites/{{siteUrl}}/searchAnalytics/query The {{siteUrl}} parameter must be URL-encoded in the actual API call. For example, https://www.example.com/ becomes https%3A%2F%2Fwww.example.com%2F. In Bubble's dynamic text system, you can use 'URL encode' formatting on a stored property URL value. For simplicity, you can also hardcode the URL-encoded siteUrl directly in the endpoint path during setup. Set the body type to JSON. A standard query body: { "startDate": "{{start_date}}", "endDate": "{{end_date}}", "dimensions": ["{{dimension}}"], "rowLimit": 100 } Dimension options: 'query' (search terms), 'page' (URL), 'device' (desktop/mobile/tablet), 'country' (country code), 'date' (daily data). You can combine up to 5 dimensions in one call. Metrics returned by default: clicks, impressions, ctr (decimal, e.g. 0.045 = 4.5%), position (average rank, e.g. 3.7). Set 'Use as' to 'Action'. To Initialize: temporarily hardcode a real access_token in the Authorization shared header (get a fresh one from the Refresh Access Token call above), set real start_date and end_date values (use dates ending at least 3 days ago to avoid the GSC data lag), and set dimension to 'query'. A successful response looks like: {"rows": [{"keys": ["search term"], "clicks": 42, "impressions": 890, "ctr": 0.047, "position": 8.3}]} If you get 403 'User does not have sufficient permissions': - The Google account that generated the refresh_token does not have access to the GSC property - Or the siteUrl in the path does not exactly match the property URL in GSC (check for trailing slash, uppercase/lowercase, www vs non-www)

gsc_search_analytics_call.json
1{
2 "method": "POST",
3 "url": "https://searchconsole.googleapis.com/webmasters/v3/sites/{{siteUrl}}/searchAnalytics/query",
4 "headers": {
5 "Authorization": "Bearer <dynamic_from_workflow>",
6 "private": true
7 },
8 "body": {
9 "startDate": "{{start_date}}",
10 "endDate": "{{end_date}}",
11 "dimensions": ["query"],
12 "rowLimit": 100,
13 "startRow": 0
14 },
15 "use_as": "Action",
16 "siteUrl_examples": {
17 "url_prefix": "URL-encoded: https%3A%2F%2Fwww.example.com%2F",
18 "domain": "URL-encoded: sc-domain%3Aexample.com"
19 }
20}

Pro tip: The Search Analytics API returns results sorted by the first metric descending (clicks) by default. To sort by a different metric, add a 'dataState': 'final' filter and pair it with startDate/endDate ending at least 3 days before today. Avoid using 'today' or 'yesterday' as endDate — GSC data for those dates is typically incomplete or returns zero rows.

Expected result: A 'Query Search Analytics' call that initializes successfully, returning a 'rows' array with keys (dimension values) and metrics (clicks, impressions, ctr, position). Both calls are now ready to be chained in a Bubble Workflow.

5

Build a Bubble Workflow to Chain Token Refresh and Display GSC Data

Create a data type in Bubble called 'GSC Row' with fields: query_term (text), page_url (text), clicks (number), impressions (number), ctr (number), position (number). Add a 'fetched_at' date field to the data type for cache tracking. Add a Repeating Group to your Bubble page. Set its Type of content to 'GSC Row'. Add text elements in the cell for query_term, clicks, impressions, and position. Format the ctr as a percentage (multiply by 100 and display with two decimal places). Create a Workflow event: 'When page is loaded'. Add actions: Action 1: Conditional token refresh — add the action only if the current access_token is expired. Check a stored 'token_expires_at' field against Current date/time. If expired or missing: - Run 'Plugins → Google OAuth - Refresh Access Token' - Make changes to App Data: store the new access_token and set token_expires_at = Current date/time + 3540 seconds Action 2: 'Plugins → Google Search Console API - Query Search Analytics'. Set Authorization dynamically: 'Bearer ' + stored access_token. Set siteUrl to your URL-encoded property URL. Set start_date to '30daysAgo' date (use Bubble's date arithmetic: Current date/time - 30 days, formatted as YYYY-MM-DD) and end_date to Current date/time - 3 days. Action 3: 'Delete a list of things' — clear old GSC Row records from the database to prevent stale data accumulation. Action 4: For each row in Action 2's result rows list, create a new GSC Row with fields populated from that row's keys array (dimension values) and metric values. Set the Repeating Group data source to 'Search for GSC Rows, sorted by Clicks descending'. Caching: on page load, first check if the most recent GSC Row's fetched_at is within the last 6 hours — if so, skip Actions 2–4 and use the cached data. This avoids unnecessary API calls (and WU costs) since GSC data has a 24–48 hour lag anyway. Add privacy rules to the GSC Row data type (Data tab → Privacy → GSC Row) to prevent public access via Bubble's Data API.

gsc_data_workflow.txt
1// Workflow: When page is loaded
2//
3// Condition A: If App Data token_expires_at < Current date/time (token expired):
4// Action 1: Plugins → Google OAuth - Refresh Access Token
5// Action 2: Make changes to App Data
6// - access_token = Action 1's access_token
7// - token_expires_at = Current date/time + 3540 seconds
8//
9// Condition B: If GSC Row newest fetched_at < Current date/time - 6 hours (cache stale):
10// Action 3: Plugins → GSC API - Query Search Analytics
11// - Authorization = "Bearer " + App Data access_token
12// - siteUrl = https%3A%2F%2Fwww.yoursite.com%2F (URL-encoded)
13// - startDate = [30 days ago formatted YYYY-MM-DD]
14// - endDate = [3 days ago formatted YYYY-MM-DD]
15// - dimensions = ["query"]
16// - rowLimit = 100
17// Action 4: Delete all existing GSC Rows
18// Action 5: Create new GSC Row for each result row
19// - query_term = row's keys[0]
20// - clicks = row's clicks
21// - impressions = row's impressions
22// - ctr = row's ctr
23// - position = row's position
24// - fetched_at = Current date/time
25//
26// Repeating Group data source: Search for GSC Rows sorted by clicks desc

Pro tip: RapidDev's team has built SEO reporting dashboards in Bubble for agencies and content teams — if you need help with multi-property GSC integration, date-range filtering UI, or combining GSC data with GA4 metrics in the same Bubble dashboard, book a free scoping call at rapidevelopers.com/contact.

Expected result: A Bubble Repeating Group displaying the top 100 organic search queries with clicks, impressions, CTR, and position pulled from the Search Analytics API — cached in the Bubble database and refreshed on a 6-hour schedule.

6

Schedule Automatic Token Refresh with a Backend Workflow (Paid Plan)

Google OAuth access_tokens expire after 1 hour. Without automatic refresh, any user who loads the Bubble GSC dashboard after the stored token expires will either see an error or wait while the page-load Workflow fetches a new token (adding latency). For a smooth production experience on a paid Bubble plan: 1. Go to Settings tab → API → check 'This app exposes a Workflow API'. This enables the Backend Workflows feature. 2. Click 'Backend workflows' in the left sidebar. Click 'Add a new API workflow'. Name it 'Refresh GSC Token'. 3. Inside the workflow, add two actions: a. Plugins → Google OAuth - Refresh Access Token b. Make changes to App Data: set access_token = Action 1's access_token, set token_expires_at = Current date/time + 3540 seconds 4. Click the clock icon on the workflow and set a recurring schedule: every 55 minutes. With this scheduler running, the token in the Bubble database is always fresh when users arrive on the dashboard. The page-load Workflow's token-expiry check (from step 5) becomes a safety net rather than a primary refresh mechanism. Free-plan users: without Backend Workflows, you can only refresh the token on page load. For users who stay on the same Bubble page for more than 1 hour, the GSC data queries will fail silently until they reload the page. If your audience typically visits the dashboard briefly (under 1 hour sessions), the page-load refresh is sufficient.

gsc_token_refresh_backend_workflow.txt
1// Backend Workflow: 'Refresh GSC Token'
2// Settings → API → expose Workflow API → checked
3// Backend Workflows → New API Workflow → 'Refresh GSC Token'
4//
5// Action 1: Plugins → Google OAuth - Refresh Access Token
6// (uses stored client_secret + refresh_token from API Connector — Private)
7// Returns: access_token
8//
9// Action 2: Make changes to App Data
10// access_token = Action 1's access_token
11// token_expires_at = Current date/time + 3540 seconds
12//
13// Recurring schedule: every 55 minutes
14// Note: Backend Workflows require a paid Bubble plan.

Pro tip: You can verify that the Backend Workflow is running correctly by checking Bubble's Logs tab → Workflow logs. Look for the 'Refresh GSC Token' entries and confirm they are completing without errors. If you see 'invalid_grant' in the logs, the refresh_token has expired and needs to be regenerated via the OAuth Playground.

Expected result: A scheduled Backend Workflow that refreshes the Google OAuth access_token every 55 minutes, ensuring all page-load GSC queries use a valid token without added latency from on-demand token refresh.

Common use cases

SEO Performance Dashboard Inside a Bubble Agency Portal

Build a Bubble app for SEO agencies that displays each client's top organic queries, impressions, clicks, and average ranking position — queried live from their GSC property and displayed in a Repeating Group with sorting and filtering options.

Bubble Prompt

Show the top 25 organic queries for client domain example.com sorted by clicks descending for the last 28 days, pulled from the Search Analytics API.

Copy this prompt to try it in Bubble

Keyword Rank Tracking Table for an Internal Bubble Tool

Display a table inside a Bubble internal tool showing the average position for target keywords over the past 90 days — allowing non-technical team members to monitor SEO ranking trends without needing access to GSC directly.

Bubble Prompt

Pull the last 90 days of GSC position data filtered to specific query keywords and display trends in a Bubble Repeating Group with weekly averages.

Copy this prompt to try it in Bubble

Low-CTR Page Discovery Report

Query the Search Analytics API with the 'page' dimension to find pages with high impressions but low CTR, then display them in a Bubble Repeating Group sorted by missed-click opportunity — helping content teams prioritize title and meta description improvements.

Bubble Prompt

Find pages with more than 500 impressions and CTR below 2% in the last 30 days, sorted by impressions, displayed in a Bubble dashboard.

Copy this prompt to try it in Bubble

Troubleshooting

Search Analytics API returns 403 'User does not have sufficient permissions' even with a valid access_token

Cause: Either (1) the Google account that generated the refresh_token does not have access to the GSC property, or (2) the siteUrl in the API path does not exactly match the property URL in Google Search Console — including trailing slash, www vs non-www, and http vs https.

Solution: Open Google Search Console and check the exact property URL displayed for your property (e.g., https://www.example.com/ with trailing slash). URL-encode this exactly: replace https:// with https%3A%2F%2F and / with %2F. If your property is a Domain property, the format is sc-domain:example.com, URL-encoded as sc-domain%3Aexample.com. Also confirm that the Google account used in the OAuth Playground is listed in GSC → Settings → Users and permissions with at least Viewer access.

Token refresh call returns 'invalid_grant' error

Cause: The refresh_token has expired or been revoked. This happens if: the Google account's password was changed, the OAuth app's consent screen is in External/Testing mode (tokens expire after 7 days), the token was manually revoked in Google Account settings, or the Google Cloud project's OAuth client was regenerated.

Solution: Go to https://developers.google.com/oauthplayground and generate a new refresh_token following the same steps as in step 2. Update the refresh_token value in the API Connector (API Connector → Google OAuth → Refresh Access Token → find the refresh_token parameter → update the value → re-initialize). Consider switching to an Internal OAuth consent screen (requires Google Workspace) to prevent future expiry.

Search Analytics query returns zero rows for recent dates

Cause: GSC data has a 2–3 day processing lag. Queries using 'today', 'yesterday', or any date within the last 2 days return zero or incomplete rows.

Solution: Always use endDate values that are at least 3 days before the current date. In Bubble date arithmetic: use 'Current date/time - 3 days' formatted as YYYY-MM-DD for the endDate, and 'Current date/time - 33 days' for a 30-day window. Also add a note in your Bubble dashboard UI to inform users that data is updated with a 2–3 day delay.

typescript
1{
2 "recommended_date_range": {
3 "startDate": "[Current date/time - 33 days, formatted YYYY-MM-DD]",
4 "endDate": "[Current date/time - 3 days, formatted YYYY-MM-DD]"
5 },
6 "note": "Never use 'today' or 'yesterday' as endDate — GSC data is not complete for these dates"
7}

'There was an issue setting up your call' when initializing the Search Analytics call in the API Connector

Cause: The access_token used during initialization has expired (tokens last only 1 hour), the siteUrl is malformed or not URL-encoded, or the Google Search Console API is not enabled in the Google Cloud project.

Solution: Run the 'Refresh Access Token' call first to get a fresh access_token (valid 1 hour). Copy it into the shared Authorization header for initialization. Verify the siteUrl in the endpoint path is URL-encoded and exactly matches your GSC property URL. Check Google Cloud Console → APIs & Services → Dashboard to confirm the Google Search Console API shows 'Enabled'.

Best practices

  • Always mark your client_secret and refresh_token as Private in the API Connector — these credentials grant full read access to your GSC data and must never appear in Bubble's Logs tab or be accessible to admin users.
  • Use the OAuth 'webmasters.readonly' scope (not 'webmasters') — granting read-only access follows the principle of least privilege and prevents any accidental write operations through the integration.
  • Never use 'today' or 'yesterday' as the endDate in Search Analytics queries — GSC data has a 2–3 day processing lag, and these dates consistently return zero or misleading data. Always end your date range at least 3 days before today.
  • Cache GSC query results in the Bubble database with a fetched_at timestamp and refresh only when the cache is older than 6–12 hours — GSC data changes slowly and re-querying on every page load wastes WUs without providing fresher data.
  • Add Bubble privacy rules to the data type storing GSC rows — without privacy rules, Bubble's public Data API exposes all records to anyone who knows the data type name.
  • Store the siteUrl (URL-encoded) in a Bubble App configuration Option Set or constant rather than hardcoding it in multiple Workflow steps — this makes it easy to switch between GSC properties or support multiple client properties in an agency tool.
  • For agency portals supporting multiple clients with different GSC properties, store client credentials (separate client_id, client_secret, refresh_token per client) in a Bubble data type with privacy rules ensuring each client can only see their own credentials.
  • Test your query body against the Search Analytics API using Google's API Explorer at https://developers.google.com/search/apis before setting it up in Bubble — this confirms the correct format and response shape before you start configuring the API Connector.

Alternatives

Frequently asked questions

Why can't Bubble use a standard Google service account for the Search Console API?

The standard Google service account flow requires signing an RSA JWT using the service account's private key — a cryptographic operation that Bubble's API Connector cannot perform natively. The refresh_token workaround (generating a token via the OAuth Playground with a Google user account that has GSC access) avoids the RSA signing requirement entirely. The tradeoff is that the refresh_token is tied to a specific user account's Google session rather than a non-expiring service account.

Can I use this integration on Bubble's free plan?

Partially. The token refresh and Search Analytics query calls work on any Bubble plan. What requires a paid plan is the Backend Workflow scheduler for automatic token renewal every 55 minutes. On the free plan, you can trigger token refresh on page load — but for users on the same page longer than 1 hour, the access_token expires and queries fail. For brief dashboard sessions (under 1 hour), the free plan is sufficient.

How many rows of GSC data can I retrieve per API call?

The Search Analytics API returns up to 25,000 rows per request using the rowLimit parameter (default is 10 if you omit rowLimit). For most Bubble dashboards, 100–500 rows is practical — displaying more than that in a Repeating Group creates a slow-rendering UI. For larger data sets, use the startRow parameter to paginate results and a 'Load More' button in Bubble.

Can I query GSC data for multiple websites in the same Bubble app?

Yes. Create a Bubble data type called 'GSC Property' with fields for the site URL (stored URL-encoded) and the associated OAuth credentials (if different accounts own different properties). In the Search Analytics Workflow, make the siteUrl parameter dynamic — populated from the selected GSC Property record. For properties owned by different Google accounts, you will need a separate refresh_token per account.

Why does the Search Analytics API sometimes return fewer rows than I expect for a dimension like 'query'?

Google samples Search Analytics data and applies privacy thresholds — queries with very few impressions may be filtered out and not returned by the API, even if they appear in the GSC UI. The API and the GSC dashboard sometimes show slightly different numbers due to this sampling. Additionally, the API default is to return the top rows by clicks — use 'rowLimit: 25000' to get as many rows as possible, and remember that the API caps results at 25,000 rows per request regardless of actual query volume.

Can I write data back to Google Search Console from Bubble (e.g., request indexing)?

The Search Analytics API is read-only — it does not support writing data. To request URL indexing from Bubble, you would use the Google Indexing API (a separate API at indexing.googleapis.com), which requires its own OAuth scope and service account setup. The GSC Search Analytics integration described here is entirely read-only.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire Bubble integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.