Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions components/google_search_console/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,10 @@ The Google Search Console API opens a treasure trove of data and insights about
- **Sync Search Results with Google Sheets**: Create a workflow that periodically pulls data from the Google Search Console API and adds it to a Google Sheet. This is useful for maintaining an evolving dataset for deeper analysis, historical reference, or sharing insights across teams without giving direct access to the Search Console.

- **Automatic Sitemap Submission**: Set up a Pipedream workflow that triggers whenever a new sitemap is generated in your content management system (CMS). The workflow can then automatically submit the sitemap to Google Search Console via API, ensuring Google has the latest structure of your site for crawling and indexing.

## Available Actions

[Retrieve Site Performance Data](./actions/retrieve-site-performance-data/README.md)
[Submit URL for Indexing](./actions/submit-url-for-indexing/README.md)


Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Google Search Console – Site Performance (Analytics) Action

This action queries **search performance data** for a verified website using the [Google Search Console API](https://developers.google.com/webmaster-tools/search-console-api-original/v3/searchanalytics/query). It allows you to extract insights like:

- Top search queries
- Click-through rates
- Page impressions
- Device types, countries, and more

---

## Use Cases

- Automate SEO reporting
- Analyze organic search trends
- Filter and break down traffic by dimensions (e.g. query, device, country)

---

## Internals

- Supports all relevant props from the [Search Analytics Query API](https://developers.google.com/webmaster-tools/search-console-api-original/v3/searchanalytics/query)
- Trims and validates all input props
- Accepts optional `dimensionFilterGroups` either as an object or JSON string
- Automatically builds the POST request body using `propsMeta` metadata
- Returns the raw Search Console API response for full access to metrics
- Accumulates and displays warnings for non-blocking input issues

---

## Auth

Requires OAuth 2.0 with the following scope: `https://www.googleapis.com/auth/webmasters.readonly`


## Endpoint
`https://searchconsole.googleapis.com/webmasters/v3/sites/{siteUrl}/searchAnalytics/query`


## 📦 Example Request Payload



```json
{

"siteUrl": "https://falc1.com/page",

"startDate": "2025-12-22",

"endDate": "2025-12-31",

"dimensions": ["query", "page", "country", "device"],

"searchType": "web",

"rowLimit": 10,

"startRow": 0,

"aggregationType": "auto",

"dataState": "final",

"dimensionFilterGroups": [
{

"groupType": "and",

"filters": [
{

"dimension": "query",

"operator": "contains",

"expression": "example"
},
{
"dimension": "country",

"operator": "equals",

"expression": "USA"
}
]
}
]
}
```

### Field Descriptions

**siteUrl**: The site you want to query data for. Must be verified in your Google Search Console account.
**startDate**: The start date of the reporting period (inclusive), in YYYY-MM-DD format.
**endDate**: The end date of the reporting period (inclusive), in YYYY-MM-DD format.
**dimensions**: The dimensions you want to break down the data by. Valid values: "query", "page", "country", "device", "searchAppearance", "date". Order matters — it affects how rows are grouped in the response.
**searchType**: The type of search data to include. Valid values: "web", "image", "video", "news", "googleNews", "discover"
**rowLimit**: Maximum number of rows to return (1–25,000)
**startRow**: Optional: Skips the first N rows — used for pagination.
**aggregationType**: Optional: How to group data. "auto" = Google's default grouping. "byPage" = Group by page (useful for getting per-page breakdowns).
**dataState**: Optional: Data freshness filter. "final" = Only finalized data (more accurate). "all" = Includes fresh but possibly incomplete data.
**dimensionFilterGroups**: Optional filter group(s) to restrict which rows are returned. Each group applies logical AND/OR across its filters.
**groupType**: Logical grouping operator for the filters inside this group. "and" = all filters must match, "or" = any filter can match
**filters**: List of individual filters to apply within the group
**dimension**: Which dimension to filter by (must match a dimension in your request)
**operator**: Filter operator — e.g., "equals", "contains", "notEquals", etc.
**expression**: Value to match against
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/**
* Fetches performance data (clicks, impressions, etc.) for a verified site
* via the Google Search Console Search Analytics API.
*
* Full usage docs in README.md
*/

import { axios } from "@pipedream/platform";
import gsConsole from "../../google_search_console.app.mjs";
import {
removeCustomPropFields, trimIfString,
} from "../../common/utils.mjs";

/*
Define prop metadata separately, including custom fields used for extended validation
and runtime behavior.

These extended fields (like `extendedType`, `postBody`, etc.) are not part of the standard
Pipedream prop schema.

A helper function (`removeCustomPropFields`) will later strip these non-standard fields,
returning only valid Pipedream props for use in the UI.

Keeping the full metadata in closure allows access to helpful context (e.g. validation rules)
during runtime.
*/
const propsMeta = {

siteUrl: {
type: "string",
extendedType: "url",
label: "Verified Site URL",
description: "Including https:// is strongly advised",
},
startDate: {
type: "string",
extendedType: "YYYY-MM-DD",
label: "Start Date (YYYY-MM-DD)",
postBody: true,
},
endDate: {
type: "string",
extendedType: "YYYY-MM-DD",
label: "End Date (YYYY-MM-DD)",
postBody: true,
},
dimensions: {
type: "string[]",
label: "Dimensions",
optional: true,
description: "e.g. ['query', 'page', 'country', 'device']",
postBody: true,
},
searchType: {
type: "string",
label: "Search Type",
optional: true,
options: [
"web",
"image",
"video",
"news",
"googleNews",
"discover",
],
default: "web",
postBody: true,
},
aggregationType: {
type: "string",
label: "Aggregation Type",
optional: true,
options: [
"auto",
"byPage",
],
postBody: true,
},
rowLimit: {
type: "integer",
label: "Max rows to return",
default: 10,
postBody: true,
},
startRow: {
type: "integer",
label: "Start row (for pagination)",
optional: true,
postBody: true,
},
dimensionFilterGroups: {
type: "object",
label: "Dimension Filters",
optional: true,
description: "Follow Search Console API structure for filters",
postBody: true,
},
dataState: {
type: "string",
label: "Data State",
optional: true,
options: [
"all",
"final",
],
default: "final",
postBody: true,
},
};

export default {
name: "Retrieve Site Performance Data",
description: "Fetches search analytics from Google Search Console for a verified site.",
key: "google_search_console-retrieve-site-performance-data",
version: "0.0.1",
type: "action",
props: {
gsConsole,
// Remove non-standard fields and expose only valid props to Pipedream UI
...removeCustomPropFields(propsMeta),
},

//=================== RUN ==============================
//======================================================

async run({ $ }) {

/*
`dimensionFilterGroups` is expected to be an object.
If a JSON string is passed instead (e.g. from UI input), attempt to parse it.
- Returns parsed object if successful
- Returns original input if not a string
- Throws a descriptive error if JSON parsing fails
*/
this.dimensionFilterGroups = this.gsConsole.parseIfJsonString(this.dimensionFilterGroups);

// Prepare the POST request payload
const body = {};

// Accumulator for non-blocking input warnings
const warnings = [];

/*
This loop:
- Trims and validates all defined props
- Skips empty optional fields
- Accumulates non-blocking warnings
- Adds valid props to the POST request payload (`body`) if marked with `postBody: true`
*/
for (let propName in propsMeta) {

// Just for convenience.
const meta = propsMeta[propName];

// Trim the value if it's a string
this[propName] = trimIfString(this[propName]);

// Skip if the prop is optional and empty (null, undefined, or blank string)
if (meta.optional === true && ((this[propName] ?? "") === "")) continue;

// Validate input (may throw or return warning messages)
const validationResult = this.gsConsole.validateUserInput(meta, this[propName]);

// Push the warnings into warnings accumulator if any.
if (validationResult.warnings) warnings.push(...validationResult.warnings);

// Include prop in the request body if marked as postBody
if (meta.postBody === true) body[propName] = this[propName];
};

// Already trimmed earlier
const url = this.siteUrl;

// Response of the POST request.
let response;

try {
response = await axios($, {
method: "POST",
url: `https://searchconsole.googleapis.com/webmasters/v3/sites/${encodeURIComponent(url)}/searchAnalytics/query`,
headers: {
"Authorization": `Bearer ${this.gsConsole.$auth.oauth_access_token}`,
"Content-Type": "application/json",
},
data: body,
});

} catch (error) {
// Identify if the error was thrown by internal validation or by the API call
const thrower = this.gsConsole.checkWhoThrewError(error);

throw new Error(`Failed to fetch data ( ${thrower.whoThrew} error ) : ${error.message}. ` + warnings.join("\n- "));
};

// Output summary and any warnings for the user
$.export("$summary", ` Fetched ${response.rows?.length || 0} rows of data. ` + warnings.join("\n- "));
return response;
},
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# 🚀 Google Indexing API – URL Submission Action

This action submits a specific URL to the **Google Indexing API** to notify Google that the content has been **updated** and should be re-crawled.

---

## ✅ Use Case

Use this action when:
- You’ve updated content on a page
- You want to request Google to reindex that URL as soon as possible

---

## 🧠 Internals

- Validates and trims the input URL
- Uses the `URL_UPDATED` type to inform Google of a content change
- Returns the raw API response
- Displays a user-friendly summary
- Accumulates and returns non-blocking warnings (e.g. unusual characters in the URL)

---

## 🔐 Auth

+Requires OAuth 2.0 with [indexing](https://www.googleapis.com/auth/indexing) scope:

## 🔗 Endpoint

[https://indexing.googleapis.com/v3/urlNotifications:publish](https://www.googleapis.com/auth/indexing)
Loading
Loading