Google Search Console ACTION
Compare Search Analytics
Compare Google Search Console traffic between two date ranges for one property and return the deltas. Fetches both periods in parallel, joins the rows on their dimension keys, and reports per-row and total clicks, impressions, ctr and position change — the period-over-period arithmetic is done for you.
Use for any question that compares two date ranges: month over month, quarter over quarter, year over year, "which queries gained or lost the most clicks", "did mobile grow", "did that update hurt us". Use Query Search Analytics for a single date range, for paging past 5000 rows, and for the hour and searchAppearance dimensions this tool does not accept. Property-level vs page-level position questions also need two Query Search Analytics calls with different aggregationType values.
Returns { current_period, previous_period, totals, rows, row_count, has_more, truncated, note }. totals carries current, previous, delta and pct_change for the whole period, computed from every fetched row rather than just the returned ones. Each row is { keys, current, previous, delta, pct_change }.
Reading the deltas. A key present in only one period gets zeros for the other, so new and lost queries both show up — but its delta.ctr and delta.position are null, because the missing period has no CTR or position to compare against (delta.clicks and delta.impressions are still real numbers). pct_change is null where the previous period was zero — not 0 and not infinity. ctr is a 0-1 fraction (0.1428 means 14.3%) and position is 1-indexed where lower is better, so a NEGATIVE position delta is an improvement; both are impression-weighted, so never re-average them across rows. Query rows always understate the real total because Google omits anonymized (rare) queries — compare with no dimensions, or by date, for true totals. truncated is true when either period hit the internal 5000-row cap, so rows and totals may be incomplete: narrow the range or add a filter. has_more is a different signal — it only means the join produced more rows than rowLimit. note warns about anonymized queries when relevant, otherwise it is null.
Mistakes. "The previous period" means the same number of days immediately before the current period: for 2026-08-01..2026-08-28 (28 days) that is 2026-07-04..2026-07-31. "The same period last year" means both dates shifted back one year. Grouping Discover by query returns a 400 — Discover has no query dimension. Comparing a range that ends today makes the current period look artificially low, because data is final only after about 2-3 days unless dataState is all. filterValue (with filterDimension/filterOperator) is applied identically to both periods and wins over advancedDimensionFilters; the equivalent prop on Query Search Analytics is named subdomainFilter for backwards compatibility.
Example. siteUrl="sc-domain:example.com", currentStartDate="2026-08-01", currentEndDate="2026-08-28", previousStartDate="2026-07-04", previousEndDate="2026-07-31", dimensions=["query"], sortBy="clicks_delta" returns totals: { current: { clicks: 74, ... }, previous: { clicks: 68, ... }, delta: { clicks: 6, ... }, pct_change: { clicks: 0.0882, ... } } and rows such as { keys: ["example brand"], current: { clicks: 41, ... }, previous: { clicks: 33, ... }, delta: { clicks: 8, ... } }.
- Action
- Read only
- OAuth
- SDK
- MCP
IMPLEMENTATION
Call this tool
Connect a user's Google Search Console account once, then configure and run Compare Search Analytics from your backend or agent.
import { PipedreamClient } from "@pipedream/sdk"
const pd = new PipedreamClient({
projectId: process.env.PIPEDREAM_PROJECT_ID!,
clientId: process.env.PIPEDREAM_CLIENT_ID!,
clientSecret: process.env.PIPEDREAM_CLIENT_SECRET!,
projectEnvironment: "production",
})
const result = await pd.actions.run({
id: "google_search_console-compare-search-analytics",
externalUserId: "{external_user_id}", // any stable ID for this user in your system
configuredProps: {
google_search_console: { authProvisionId: "apn_xxxxxxx" },
siteUrl: "Property (siteUrl)",
currentStartDate: "Current Period Start Date (YYYY-MM-DD)",
},
})
console.log(result)curl -X POST https://api.pipedream.com/v1/connect/{project_id}/actions/run \
-H "Content-Type: application/json" \
-H "X-PD-Environment: production" \
-H "Authorization: Bearer {access_token}" \
-d '{
"external_user_id": "{external_user_id}",
"id": "google_search_console-compare-search-analytics",
"configured_props": {
"google_search_console": { "authProvisionId": "apn_xxxxxxx" },
"siteUrl": "Property (siteUrl)",
"currentStartDate": "Current Period Start Date (YYYY-MM-DD)"
}
}'// accessToken: mint a short-lived token with the Connect SDK — see the MCP guide
const transport = new StreamableHTTPClientTransport(
new URL("https://remote.mcp.pipedream.net/v3"),
{
requestInit: {
headers: {
Authorization: `Bearer ${accessToken}`,
"x-pd-project-id": "{project_id}",
"x-pd-environment": "production",
"x-pd-external-user-id": "{external_user_id}", // any stable ID for this user in your system
"x-pd-app-slug": "google_search_console",
},
},
},
)
const mcp = new Client({ name: "my-agent", version: "1.0.0" })
await mcp.connect(transport)
const { tools } = await mcp.listTools()
// listTools() hands your model this tool's input schema, so it can
// fill the arguments itself:
const result = await mcp.callTool({
name: "google_search_console-compare-search-analytics",
arguments: {
siteUrl: "Property (siteUrl)",
currentStartDate: "Current Period Start Date (YYYY-MM-DD)",
},
})SCHEMA
Inputs
Pipedream supplies the connected account. Your application provides the operation-specific values below. Dynamic inputs are resolved against that user's account.
| Property | Type | Description |
|---|---|---|
siteUrl Property (siteUrl) | string | Exact property identifier from List Sites — sc-domain:example.com for a domain property, or a URL-prefix such as https://www.example.com/ (trailing slash; scheme and subdomain must match exactly, or the call 403s). Copy it verbatim, never construct it. For traffic questions prefer the domain property when one exists: it covers all subdomains and protocols. Required |
currentStartDate Current Period Start Date (YYYY-MM-DD) | string | First day of the RECENT period, inclusive, in YYYY-MM-DD Pacific Time — e.g. 2026-08-01. Required |
currentEndDate Current Period End Date (YYYY-MM-DD) | string | Last day of the RECENT period, inclusive — e.g. 2026-08-28. Data is final only after 2-3 days, so avoid ending on today unless dataState is all. Required |
previousStartDate Previous Period Start Date (YYYY-MM-DD) | string | First day of the BASELINE period, inclusive. For "the previous period" use the same number of days immediately before the current one — for 2026-08-01..2026-08-28 that is 2026-07-04. For "the same period last year", shift currentStartDate back a year: 2025-08-01. Required |
previousEndDate Previous Period End Date (YYYY-MM-DD) | string | Last day of the BASELINE period, inclusive. For "the previous period" it is the day before currentStartDate — for a current period starting 2026-08-01 that is 2026-07-31. For "the same period last year", shift currentEndDate back a year. Required |
dimensions Dimensions | string[] | How to group the compared rows; each row's keys lines up positionally with this list. Leave empty to compare one totals row per period — the right choice for "how did traffic change overall". Use query for which queries gained or lost, page for page-level movement, device for mobile vs desktop, country for market shifts, date for a day-by-day pair-up. hour and searchAppearance are not supported here — use Query Search Analytics. Optional |
searchType Search Type | string | Which Google surface to report on. web (default) is normal Google Search; discover is the Discover feed (no query dimension); googleNews is news.google.com, news is the News tab of Google Search. Sent to the API as type. Optional |
dataState Data State | string | Which data to include, applied to both periods. final (default) returns only finalized data, which lags roughly 2-3 days. all also includes the most recent, not-yet-final days — use it only when the user explicitly wants recent or partial numbers; it makes a current period ending today look incomplete rather than absent. Optional |
filterDimension Filter Dimension | string | Dimension the single-filter shortcut applies to; default page. Filtering does not require grouping by the same dimension — you can filter by page while grouping by query. page expressions match the FULL URL, scheme and host included, not a path. Optional |
filterOperator Filter Operator | string | How the filter value is compared. String comparison is case-insensitive. includingRegex/excludingRegex use RE2 syntax (no lookahead/lookbehind). Default contains. Optional |
filterValue Filter Value | string | The value to filter on, for ANY dimension — not just subdomains (Query Search Analytics keeps the legacy key subdomainFilter). Combined with filterDimension and filterOperator into one filter, e.g. filterDimension: page, filterOperator: contains, value https://www.example.com/blog/. page expressions match the FULL URL, scheme and host included, not a path. Setting this makes advancedDimensionFilters ignored. Optional |
advancedDimensionFilters Advanced Dimension Filters | string | JSON for multi-condition filtering, used only when the single-filter shortcut is empty. Accepts either a bare array of filters, which is ANDed into one group — e.g. [{"dimension":"country","operator":"equals","expression":"usa"},{"dimension":"device","operator":"equals","expression":"MOBILE"}] — or the raw API dimensionFilterGroups array, e.g. [{"groupType":"and","filters":[{"dimension":"page","operator":"contains","expression":"/blog/"}]}]. The API only supports groupType: "and"; there is no OR. Regex operators use RE2. Optional |
sortBy Sort By | string | How to order the returned rows; defaults to clicks_delta. The *_delta options sort by ABSOLUTE change, so the biggest gains and losses both appear at the top — read the sign of delta to tell them apart. Under ctr_delta and position_delta, rows whose delta is null (a key present in only one period) sort last, so use clicks_delta to surface new and lost queries. current_clicks sorts by current-period clicks descending — right for "top queries, with their change". Optional |
rowLimit Max Rows | integer | How many joined rows to return, after sorting; defaults to 50. Caps the OUTPUT only — up to 5000 rows per period are always fetched, so the totals cover everything even when the row list is short, unless truncated is true. has_more means the join produced more rows than were returned. Optional |
REFERENCE
Tool details
Behavior hints are published with the component in the Pipedream registry and surface as MCP tool annotations, so an agent can reason about a tool before it calls it.
- Registry key
- google_search_console-compare-search-analytics
- Version
- 0.0.1
- App
- Google Search Console
- Authentication
- OAuth
- Read-only
- Yes
- Destructive
- No
- Open world
- Yes
- Source
- View on GitHub ↗