From 1bd271dea1d67d3421a293134654d323b45fc637 Mon Sep 17 00:00:00 2001 From: Dan H Date: Mon, 15 Jun 2026 13:38:16 +0100 Subject: [PATCH 1/9] Add Google Search Console plugin --- .../v1/dataStreams/countryBreakdown.json | 31 + .../v1/dataStreams/deviceBreakdown.json | 31 + .../v1/dataStreams/pageDistribution.json | 59 ++ .../dataStreams/pagePerformanceOverTime.json | 59 ++ .../dataStreams/pagePerformanceSummary.json | 59 ++ .../v1/dataStreams/pageUrLs.json | 30 + .../v1/dataStreams/pages.json | 30 + .../previousPeriodPagePerformance.json | 59 ++ .../previousPeriodPerformanceOverTime.json | 31 + .../previousPeriodQueriesByPage.json | 59 ++ .../v1/dataStreams/queries.json | 31 + .../v1/dataStreams/queriesByPage.json | 60 ++ .../scripts/postRequest/countryBreakdown.js | 9 + .../scripts/postRequest/deviceBreakdown.js | 9 + .../scripts/postRequest/pageDistribution.js | 17 + .../postRequest/pagePerformanceOverTime.js | 9 + .../scripts/postRequest/pageUrLs.js | 4 + .../dataStreams/scripts/postRequest/pages.js | 9 + .../previousPeriodPerformanceOverTime.js | 9 + .../previousPeriodQueriesByPage.js | 9 + .../scripts/postRequest/script1.js | 9 + .../scripts/postRequest/script2.js | 11 + .../postRequest/sitePerformanceOverTime.js | 11 + .../postRequest/sitePerformanceSummary.js | 8 + .../dataStreams/sitePerformanceOverTime.json | 46 ++ .../dataStreams/sitePerformanceSummary.json | 26 + .../v1/defaultContent/manifest.json | 12 + .../v1/defaultContent/pageOverview.dash.json | 646 ++++++++++++++++++ .../v1/defaultContent/scopes.json | 19 + .../v1/defaultContent/siteOverview.dash.json | 398 +++++++++++ plugins/GoogleSearchConsole/v1/docs/README.md | 95 +++ plugins/GoogleSearchConsole/v1/icon.svg | 1 + .../v1/indexDefinitions/default.json | 19 + plugins/GoogleSearchConsole/v1/metadata.json | 42 ++ plugins/GoogleSearchConsole/v1/ui.json | 39 ++ 35 files changed, 1996 insertions(+) create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/countryBreakdown.json create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/deviceBreakdown.json create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/pageDistribution.json create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceOverTime.json create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceSummary.json create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/pageUrLs.json create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/pages.json create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPagePerformance.json create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPerformanceOverTime.json create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodQueriesByPage.json create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/queries.json create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/queriesByPage.json create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/countryBreakdown.js create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/deviceBreakdown.js create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageDistribution.js create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pagePerformanceOverTime.js create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageUrLs.js create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pages.js create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodPerformanceOverTime.js create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodQueriesByPage.js create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script1.js create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script2.js create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceOverTime.js create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceSummary.js create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceOverTime.json create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceSummary.json create mode 100644 plugins/GoogleSearchConsole/v1/defaultContent/manifest.json create mode 100644 plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json create mode 100644 plugins/GoogleSearchConsole/v1/defaultContent/scopes.json create mode 100644 plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json create mode 100644 plugins/GoogleSearchConsole/v1/docs/README.md create mode 100644 plugins/GoogleSearchConsole/v1/icon.svg create mode 100644 plugins/GoogleSearchConsole/v1/indexDefinitions/default.json create mode 100644 plugins/GoogleSearchConsole/v1/metadata.json create mode 100644 plugins/GoogleSearchConsole/v1/ui.json diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/countryBreakdown.json b/plugins/GoogleSearchConsole/v1/dataStreams/countryBreakdown.json new file mode 100644 index 00000000..ccb05ad9 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/countryBreakdown.json @@ -0,0 +1,31 @@ +{ + "name": "countryBreakdown", + "displayName": "Country breakdown", + "description": "Returns search performance metrics grouped by country", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "postBody": { + "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", + "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", + "dimensions": [ + "country" + ], + "rowLimit": 25000, + "dataState": "final" + }, + "postRequestScript": "postRequest/countryBreakdown.js", + "getArgs": [], + "headers": [] + }, + "providesPluginDiagnostics": true, + "timeframes": true, + "tags": [] +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/deviceBreakdown.json b/plugins/GoogleSearchConsole/v1/dataStreams/deviceBreakdown.json new file mode 100644 index 00000000..93b605a8 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/deviceBreakdown.json @@ -0,0 +1,31 @@ +{ + "name": "deviceBreakdown", + "displayName": "Device breakdown", + "description": "Returns search performance metrics grouped by device type", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "postBody": { + "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", + "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", + "dimensions": [ + "device" + ], + "rowLimit": 25000, + "dataState": "final" + }, + "postRequestScript": "postRequest/deviceBreakdown.js", + "getArgs": [], + "headers": [] + }, + "providesPluginDiagnostics": true, + "timeframes": true, + "tags": [] +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/pageDistribution.json b/plugins/GoogleSearchConsole/v1/dataStreams/pageDistribution.json new file mode 100644 index 00000000..2d118eda --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/pageDistribution.json @@ -0,0 +1,59 @@ +{ + "name": "pageDistribution", + "displayName": "Page distribution", + "description": "Returns a distribution of queries by search ranking position for the selected page", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "getArgs": [], + "headers": [], + "postBody": { + "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", + "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", + "dimensions": [ + "query" + ], + "dimensionFilterGroups": [ + { + "filters": [ + { + "dimension": "page", + "operator": "equals", + "expression": "{{scope?.[0]?.name}}" + } + ] + } + ], + "rowLimit": 25000 + }, + "postRequestScript": "postRequest/pageDistribution.js" + }, + "providesPluginDiagnostics": true, + "timeframes": true, + "tags": [], + + "ui": [ + { + "name": "scope", + "objectLimit": 1, + "label": "Scope", + "type": "objects", + "matches": { + "sourceType": { + "type": "equals", + "value": "gsc-page" + } + }, + "validation": { + "required": true + } + } + ] +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceOverTime.json b/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceOverTime.json new file mode 100644 index 00000000..6d93f5d8 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceOverTime.json @@ -0,0 +1,59 @@ +{ + "name": "pagePerformanceOverTime", + "displayName": "Page performance over time", + "description": "Returns daily clicks, impressions and CTR trends for the selected page", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "postBody": { + "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", + "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", + "dimensions": [ + "date" + ], + "dimensionFilterGroups": [ + { + "filters": [ + { + "dimension": "page", + "operator": "equals", + "expression": "{{scope?.[0]?.name}}" + } + ] + } + ], + "rowLimit": 25000 + }, + "postRequestScript": "postRequest/pagePerformanceOverTime.js", + "getArgs": [], + "headers": [] + }, + "providesPluginDiagnostics": true, + "timeframes": true, + "tags": [], + + "ui": [ + { + "name": "scope", + "objectLimit": 1, + "label": "Scope", + "type": "objects", + "matches": { + "sourceType": { + "type": "equals", + "value": "gsc-page" + } + }, + "validation": { + "required": true + } + } + ] +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceSummary.json b/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceSummary.json new file mode 100644 index 00000000..675ddf7f --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceSummary.json @@ -0,0 +1,59 @@ +{ + "name": "pagePerformanceSummary", + "displayName": "Page performance summary", + "description": "Returns performance metrics for a given page", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "getArgs": [], + "headers": [], + "postBody": { + "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", + "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", + "dimensions": [ + "page" + ], + "dimensionFilterGroups": [ + { + "filters": [ + { + "dimension": "page", + "operator": "equals", + "expression": "{{scope?.[0]?.name}}" + } + ] + } + ], + "rowLimit": 25000 + }, + "postRequestScript": "postRequest/script1.js" + }, + "providesPluginDiagnostics": true, + "timeframes": true, + "tags": [], + + "ui": [ + { + "name": "scope", + "objectLimit": 1, + "label": "Scope", + "type": "objects", + "matches": { + "sourceType": { + "type": "equals", + "value": "gsc-page" + } + }, + "validation": { + "required": true + } + } + ] +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/pageUrLs.json b/plugins/GoogleSearchConsole/v1/dataStreams/pageUrLs.json new file mode 100644 index 00000000..e4a5de8e --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/pageUrLs.json @@ -0,0 +1,30 @@ +{ + "name": "pageUrLs", + "displayName": "Page URLs", + "description": "Returns a list off URLs with impressions in the last year", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "postBody": { + "startDate": "{{new Date(Date.now() - 365 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]}}", + "endDate": "{{new Date().toISOString().split('T')[0]}}", + "dimensions": [ + "page" + ], + "rowLimit": 25 + }, + "postRequestScript": "postRequest/pageUrLs.js", + "getArgs": [], + "headers": [] + }, + "timeframes": false, + "providesPluginDiagnostics": true, + "tags": [] +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/pages.json b/plugins/GoogleSearchConsole/v1/dataStreams/pages.json new file mode 100644 index 00000000..0993d17f --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/pages.json @@ -0,0 +1,30 @@ +{ + "name": "pages", + "displayName": "Pages", + "description": "Returns a complete list of pages with performance metrics", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "postBody": { + "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", + "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", + "dimensions": [ + "page" + ], + "rowLimit": 25000 + }, + "postRequestScript": "postRequest/pages.js", + "getArgs": [], + "headers": [] + }, + "providesPluginDiagnostics": true, + "timeframes": true, + "tags": [] +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPagePerformance.json b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPagePerformance.json new file mode 100644 index 00000000..9ffed41f --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPagePerformance.json @@ -0,0 +1,59 @@ +{ + "name": "previousPeriodPagePerformance", + "displayName": "Previous period page performance", + "description": "Returns a summary of performance for the previous period of a given timeframe for the selected page", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "getArgs": [], + "headers": [], + "postBody": { + "startDate": "{{new Date(new Date(timeframe.start).getTime() - (new Date(timeframe.end).getTime() - new Date(timeframe.start).getTime()) - 86400000).toISOString().split('T')[0]}}", + "endDate": "{{new Date(new Date(timeframe.start).getTime() - 86400000).toISOString().split('T')[0]}}", + "dimensions": ["page"], + "dimensionFilterGroups": [ + { + "filters": [ + { + "dimension": "page", + "operator": "equals", + "expression": "{{scope?.[0]?.name}}" + } + ] + } + ], + "rowLimit": 25000 + }, + "postRequestScript": "postRequest/script1.js" + }, + "timeframes": true, + "providesPluginDiagnostics": true, + "tags": [], + "visibility": { + "type": "hidden" + }, + "ui": [ + { + "name": "scope", + "objectLimit": 1, + "label": "Scope", + "type": "objects", + "matches": { + "sourceType": { + "type": "equals", + "value": "gsc-page" + } + }, + "validation": { + "required": true + } + } + ] +} diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPerformanceOverTime.json b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPerformanceOverTime.json new file mode 100644 index 00000000..63f862a7 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPerformanceOverTime.json @@ -0,0 +1,31 @@ +{ + "name": "previousPeriodPerformanceOverTime", + "displayName": "Previous period performance over time", + "description": "Returns daily performance for the previous period of a given timeframe for the selected page", + "baseDataSourceName": "httpRequestUnscoped", + "visibility": { + "type": "hidden" + }, + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "postBody": { + "startDate": "{{new Date(new Date(timeframe.start).getTime() - (new Date(timeframe.end).getTime() - new Date(timeframe.start).getTime()) - 86400000).toISOString().split('T')[0]}}", + "endDate": "{{new Date(new Date(timeframe.start).getTime() - 86400000).toISOString().split('T')[0]}}", + "dimensions": ["date"], + "rowLimit": 25000 + }, + "postRequestScript": "postRequest/previousPeriodPerformanceOverTime.js", + "getArgs": [], + "headers": [] + }, + "timeframes": true, + "providesPluginDiagnostics": true, + "tags": [] +} diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodQueriesByPage.json b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodQueriesByPage.json new file mode 100644 index 00000000..b029a1f3 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodQueriesByPage.json @@ -0,0 +1,59 @@ +{ + "name": "previousPeriodQueriesByPage", + "displayName": "Previous period queries by page", + "description": "Returns queries for the previous period of a given timeframe for the selected page", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "getArgs": [], + "headers": [], + "postBody": { + "startDate": "{{new Date(new Date(timeframe.start).getTime() - (new Date(timeframe.end).getTime() - new Date(timeframe.start).getTime()) - 86400000).toISOString().split('T')[0]}}", + "endDate": "{{new Date(new Date(timeframe.start).getTime() - 86400000).toISOString().split('T')[0]}}", + "dimensions": ["query"], + "dimensionFilterGroups": [ + { + "filters": [ + { + "dimension": "page", + "operator": "equals", + "expression": "{{scope?.[0]?.name}}" + } + ] + } + ], + "rowLimit": 25000 + }, + "postRequestScript": "postRequest/previousPeriodQueriesByPage.js" + }, + "timeframes": true, + "providesPluginDiagnostics": true, + "tags": [], + "visibility": { + "type": "hidden" + }, + "ui": [ + { + "name": "scope", + "objectLimit": 1, + "label": "Scope", + "type": "objects", + "matches": { + "sourceType": { + "type": "equals", + "value": "gsc-page" + } + }, + "validation": { + "required": true + } + } + ] +} diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/queries.json b/plugins/GoogleSearchConsole/v1/dataStreams/queries.json new file mode 100644 index 00000000..8eb1b87e --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/queries.json @@ -0,0 +1,31 @@ +{ + "name": "queries", + "displayName": "Queries", + "description": "Returns a complete list of queries with performance metrics", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "postBody": { + "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", + "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", + "dimensions": [ + "query" + ], + "rowLimit": 25000, + "dataState": "final" + }, + "postRequestScript": "postRequest/script2.js", + "getArgs": [], + "headers": [] + }, + "providesPluginDiagnostics": true, + "timeframes": true, + "tags": [] +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/queriesByPage.json b/plugins/GoogleSearchConsole/v1/dataStreams/queriesByPage.json new file mode 100644 index 00000000..a296ede9 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/queriesByPage.json @@ -0,0 +1,60 @@ +{ + "name": "queriesByPage", + "displayName": "Queries by page", + "description": "Returns query metrics for the selected page", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "postBody": { + "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", + "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", + "dimensions": [ + "query" + ], + "dimensionFilterGroups": [ + { + "filters": [ + { + "dimension": "page", + "operator": "equals", + "expression": "{{scope?.[0]?.rawId?.[0]}}" + } + ] + } + ], + "rowLimit": 25000, + "dataState": "final" + }, + "postRequestScript": "postRequest/script2.js", + "getArgs": [], + "headers": [] + }, + "providesPluginDiagnostics": true, + "timeframes": true, + "tags": [], + + "ui": [ + { + "name": "scope", + "objectLimit": 1, + "label": "Page", + "type": "objects", + "matches": { + "sourceType": { + "type": "equals", + "value": "gsc-page" + } + }, + "validation": { + "required": true + } + } + ] +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/countryBreakdown.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/countryBreakdown.js new file mode 100644 index 00000000..e573e04f --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/countryBreakdown.js @@ -0,0 +1,9 @@ +const rows = data.rows ?? []; + +result = rows.map(row => ({ + Country: row.keys?.[0], + Clicks: row.clicks, + Impressions: row.impressions, + CTR: Number((row.ctr * 100).toFixed(2)), + Position: Number(row.position.toFixed(2)) +})); \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/deviceBreakdown.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/deviceBreakdown.js new file mode 100644 index 00000000..0c3f4ee2 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/deviceBreakdown.js @@ -0,0 +1,9 @@ +const rows = data.rows ?? []; + +result = rows.map(row => ({ + Device: row.keys?.[0], + Clicks: row.clicks, + Impressions: row.impressions, + CTR: Number((row.ctr * 100).toFixed(2)), + Position: Number(row.position.toFixed(2)) +})); \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageDistribution.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageDistribution.js new file mode 100644 index 00000000..aead2978 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageDistribution.js @@ -0,0 +1,17 @@ +const rows = data.rows ?? []; + +result = rows.map(row => { + const position = row.position ?? 0; + + let Bucket = "51+"; + + if (position <= 3) Bucket = "1-3"; + else if (position <= 10) Bucket = "4-10"; + else if (position <= 20) Bucket = "11-20"; + else if (position <= 50) Bucket = "21-50"; + + return { + Bucket, + Queries: 1 + }; +}); \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pagePerformanceOverTime.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pagePerformanceOverTime.js new file mode 100644 index 00000000..aee4786c --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pagePerformanceOverTime.js @@ -0,0 +1,9 @@ +const rows = data.rows ?? []; + +result = rows.map(row => ({ + Date: new Date(row.keys?.[0]), + Clicks: row.clicks, + Impressions: row.impressions, + CTR: Number((row.ctr * 100).toFixed(2)), + Position: Number(row.position.toFixed(1)) +})); \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageUrLs.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageUrLs.js new file mode 100644 index 00000000..4ea7a9c6 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageUrLs.js @@ -0,0 +1,4 @@ +result = (data.rows || []).map(row => ({ + label: row.keys?.[0] || "", + value: row.keys?.[0] || "" +})); \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pages.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pages.js new file mode 100644 index 00000000..9cabe3ee --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pages.js @@ -0,0 +1,9 @@ +const rows = data.rows ?? []; + +result = rows.map(row => ({ + Page: row.keys?.[0], + Clicks: row.clicks, + Impressions: row.impressions, + CTR: Number((row.ctr * 100).toFixed(2)), + Position: Number(row.position.toFixed(2)) +})); \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodPerformanceOverTime.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodPerformanceOverTime.js new file mode 100644 index 00000000..76f3cd26 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodPerformanceOverTime.js @@ -0,0 +1,9 @@ +const rows = data.rows ?? []; + +result = rows.map(row => ({ + Date: row.keys?.[0], + Clicks: row.clicks, + Impressions: row.impressions, + CTR: Number((row.ctr * 100).toFixed(2)), + Position: Number(row.position.toFixed(1)) +})); \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodQueriesByPage.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodQueriesByPage.js new file mode 100644 index 00000000..9cad4f37 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodQueriesByPage.js @@ -0,0 +1,9 @@ +const rows = data.rows ?? []; + +result = rows.map(row => ({ + Query: row.keys?.[0], + Clicks: row.clicks, + Impressions: row.impressions, + CTR: Number((row.ctr * 100).toFixed(2)), + Position: Number(row.position.toFixed(1)) +})); \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script1.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script1.js new file mode 100644 index 00000000..bac7be20 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script1.js @@ -0,0 +1,9 @@ +const rows = data.rows ?? []; + +result = rows.map(row => ({ + Page: row.keys?.[0], + Clicks: row.clicks, + Impressions: row.impressions, + CTR: Number((row.ctr * 100).toFixed(2)), + Position: Number(row.position.toFixed(1)) +})); \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script2.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script2.js new file mode 100644 index 00000000..63a2d10b --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script2.js @@ -0,0 +1,11 @@ +const rows = data.rows ?? []; + +result = rows.map(row => { + return { + Query: row.keys?.[0], + Clicks: row.clicks, + Impressions: row.impressions, + CTR: Number((row.ctr * 100).toFixed(2)), + Position: Number(row.position.toFixed(2)) + }; +}); \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceOverTime.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceOverTime.js new file mode 100644 index 00000000..8fe3ebb4 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceOverTime.js @@ -0,0 +1,11 @@ +const rows = data.rows ?? []; + +result = rows.map(row => { + return { + Date: new Date(row.keys?.[0]), + Clicks: row.clicks, + Impressions: row.impressions, + CTR: Number((row.ctr * 100).toFixed(2)), + Position: Number(row.position.toFixed(2)) + }; +}); \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceSummary.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceSummary.js new file mode 100644 index 00000000..6f970d6c --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceSummary.js @@ -0,0 +1,8 @@ +const row = data.rows?.[0] ?? {}; + +result = [{ + Impressions: row.impressions ?? 0, + Clicks: row.clicks ?? 0, + CTR: Number(((row.ctr ?? 0) * 100).toFixed(2)), + Position: Number((row.position ?? 0).toFixed(2)) +}]; \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceOverTime.json b/plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceOverTime.json new file mode 100644 index 00000000..1e3761e9 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceOverTime.json @@ -0,0 +1,46 @@ +{ + "name": "sitePerformanceOverTime", + "displayName": "Site performance over time", + "description": "Returns performance metrics for the entire site over the specified timeframe", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "postBody": { + "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", + "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", + "dimensions": [ + "date" + ], + "rowLimit": 25000, + "dataState": "final" + }, + "postRequestScript": "postRequest/sitePerformanceOverTime.js", + "getArgs": [], + "headers": [] + }, + "metadata": [ + { + "shape": [ + "date", + { + "format": "dd/MM/yyyy", + "timeZone": "Etc/UTC" + } + ], + "name": "Date" + }, + { + "pattern": ".*" + } + ], + "providesPluginDiagnostics": true, + "timeframes": true, + "tags": [] +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceSummary.json b/plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceSummary.json new file mode 100644 index 00000000..159cfce9 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceSummary.json @@ -0,0 +1,26 @@ +{ + "name": "sitePerformanceSummary", + "displayName": "Site performance summary", + "description": "Returns a summary of metrics for the site", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "postBody": { + "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", + "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}" + }, + "postRequestScript": "postRequest/sitePerformanceSummary.js", + "getArgs": [], + "headers": [] + }, + "providesPluginDiagnostics": true, + "timeframes": true, + "tags": [] +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/defaultContent/manifest.json b/plugins/GoogleSearchConsole/v1/defaultContent/manifest.json new file mode 100644 index 00000000..51b75d86 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/defaultContent/manifest.json @@ -0,0 +1,12 @@ +{ + "items": [ + { + "name": "siteOverview", + "type": "dashboard" + }, + { + "name": "pageOverview", + "type": "dashboard" + } + ] +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json b/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json new file mode 100644 index 00000000..577bf7eb --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json @@ -0,0 +1,646 @@ +{ + "name": "Page Overview", + "schemaVersion": "1.5", + "dashboard": { + "_type": "layout/grid", + "contents": [ + { + "static": false, + "w": 5, + "moved": false, + "h": 1, + "x": 0, + "y": 0, + "i": "6a80af30-0353-4b51-afb5-cd4a8f2f9fc8", + "z": 0, + "config": { + "variables": [ + "{{variables.[Google Search Console Page]}}" + ], + "dataStream": { + "name": "pagePerformance", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Google Search Console Page]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Google Search Console Pages]}}" + } + }, + "id": "{{dataStreams.pagePerformanceSummary}}", + "pluginConfigId": "{{configId}}" + }, + "_type": "tile/data-stream", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "baseTile": "data-stream-base-tile", + "title": "Page summary", + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "columnOrder": [ + "Clicks", + "Impressions", + "CTR", + "Position" + ], + "resizedColumns": { + "columnWidths": { + "CTR": 193, + "Impressions": 168, + "Page": 175 + } + }, + "hiddenColumns": [ + "Page" + ] + } + } + } + } + }, + { + "static": false, + "moved": false, + "w": 5, + "h": 1, + "x": 0, + "i": "7bfbf121-4b54-4e05-b0c6-b49976fbe0fe", + "y": 1, + "z": 0, + "config": { + "variables": [ + "{{variables.[Google Search Console Page]}}" + ], + "dataStream": { + "dataSourceConfig": { + "version": "2.0", + "tables": [ + { + "config": { + "variables": [ + "{{variables.[Google Search Console Page]}}" + ], + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "name": "previousPeriodPagePerformance", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Google Search Console Page]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Google Search Console Pages]}}" + } + }, + "id": "{{dataStreams.previousPeriodPagePerformance}}", + "pluginConfigId": "{{configId}}" + } + }, + "tableName": "dataset1" + }, + { + "config": { + "_type": "tile/data-stream", + "variables": [ + "{{variables.[Google Search Console Page]}}" + ], + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "name": "pagePerformance", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Google Search Console Page]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Google Search Console Pages]}}" + } + }, + "id": "{{dataStreams.pagePerformanceSummary}}", + "pluginConfigId": "{{configId}}" + } + }, + "tableName": "dataset2" + } + ], + "sql": "WITH previous_period AS (\r\n SELECT\r\n COALESCE(SUM(Clicks), 0) AS Clicks,\r\n COALESCE(SUM(Impressions), 0) AS Impressions,\r\n COALESCE(SUM(Clicks) / NULLIF(SUM(Impressions), 0) * 100, 0) AS CTR,\r\n AVG(Position) AS Position\r\n FROM dataset1\r\n),\r\n\r\ncurrent_period AS (\r\n SELECT\r\n COALESCE(SUM(Clicks), 0) AS Clicks,\r\n COALESCE(SUM(Impressions), 0) AS Impressions,\r\n COALESCE(SUM(Clicks) / NULLIF(SUM(Impressions), 0) * 100, 0) AS CTR,\r\n AVG(Position) AS Position\r\n FROM dataset2\r\n)\r\n\r\nSELECT\r\n CASE\r\n WHEN previous_period.Clicks = 0 THEN 0\r\n ELSE ROUND(((current_period.Clicks - previous_period.Clicks) / previous_period.Clicks) * 100, 2)\r\n END AS \"Clicks Change %\",\r\n\r\n CASE\r\n WHEN previous_period.Impressions = 0 THEN 0\r\n ELSE ROUND(((current_period.Impressions - previous_period.Impressions) / previous_period.Impressions) * 100, 2)\r\n END AS \"Impressions Change %\",\r\n\r\n CASE\r\n WHEN previous_period.CTR = 0 THEN 0\r\n ELSE ROUND(((current_period.CTR - previous_period.CTR) / previous_period.CTR) * 100, 2)\r\n END AS \"CTR Change %\",\r\n\r\n CASE\r\n WHEN previous_period.Position IS NULL OR current_period.Position IS NULL THEN 0\r\n ELSE ROUND(previous_period.Position - current_period.Position, 1)\r\n END AS \"Position Change\"\r\n\r\nFROM previous_period\r\nCROSS JOIN current_period" + }, + "id": "datastream-sql" + }, + "scope": { + "query": "g.V().has('id', within(ids_MI6UfjAoqy17Fe9Ug6ST))", + "bindings": { + "ids_MI6UfjAoqy17Fe9Ug6ST": [ + "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" + ] + }, + "queryDetail": { + "ids": [ + "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" + ] + } + }, + "_type": "tile/data-stream", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "title": "Organic search performance", + "baseTile": "data-stream-base-tile", + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "columnOrder": [ + "Clicks Change %", + "Impressions Change %", + "CTR Change %", + "Position Change" + ], + "resizedColumns": { + "columnWidths": { + "Position Change": 135, + "Impressions Change %": 177, + "CTR Change %": 122, + "Clicks Change %": 135 + } + }, + "hiddenColumns": [] + } + } + } + } + }, + { + "static": false, + "w": 5, + "moved": false, + "h": 2, + "x": 0, + "y": 2, + "i": "9665d5a3-74fd-484d-992c-64d2e34ad365", + "z": 0, + "config": { + "variables": [ + "{{variables.[Google Search Console Page]}}" + ], + "dataStream": { + "dataSourceConfig": { + "version": "2.0", + "tables": [ + { + "config": { + "variables": [ + "{{variables.[Google Search Console Page]}}" + ], + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "name": "previousPeriodQueriesByPage", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Google Search Console Page]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Google Search Console Pages]}}" + } + }, + "id": "{{dataStreams.previousPeriodQueriesByPage}}", + "pluginConfigId": "{{configId}}" + } + }, + "tableName": "dataset1" + }, + { + "config": { + "variables": [ + "{{variables.[Google Search Console Page]}}" + ], + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "name": "queriesByPage", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Google Search Console Page]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Google Search Console Pages]}}" + } + }, + "id": "{{dataStreams.queriesByPage}}", + "pluginConfigId": "{{configId}}" + } + }, + "tableName": "dataset2" + } + ], + "sql": "SELECT\r\n c.Query,\r\n ROUND(p.Position - c.Position, 1) AS PositionChange,\r\n c.Position AS CurrentPosition,\r\n p.Position AS PreviousPosition,\r\n c.Clicks,\r\n c.Impressions\r\nFROM dataset1 c\r\nINNER JOIN dataset2 p\r\n ON c.Query = p.Query\r\nWHERE\r\n c.Impressions > 0\r\n OR p.Impressions > 0\r\nORDER BY PositionChange DESC\r\nLIMIT 10" + }, + "id": "datastream-sql" + }, + "scope": { + "query": "g.V().has('id', within(ids_d0XpnAS5M7Up3bmNCZUB))", + "bindings": { + "ids_d0XpnAS5M7Up3bmNCZUB": [ + "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" + ] + }, + "queryDetail": { + "ids": [ + "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" + ] + } + }, + "_type": "tile/data-stream", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "baseTile": "data-stream-base-tile", + "title": "Biggest Ranking Changes", + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "columnOrder": [ + "Query", + "PositionChange", + "CurrentPosition", + "PreviousPosition" + ], + "resizedColumns": { + "columnWidths": { + "Impressions": 112, + "Previous Pos": 98, + "PreviousPosition": 98, + "PositionImprovement": 173, + "Query": 105, + "CurrentPosition": 97, + "PositionChange": 101, + "Current Pos": 92 + } + }, + "hiddenColumns": [ + "Clicks", + "Impressions" + ] + } + } + } + } + }, + { + "static": false, + "w": 4, + "moved": false, + "h": 2, + "x": 0, + "y": 4, + "i": "6b7519f4-4f66-4ac5-9dab-1c8ff03aaa44", + "z": 0, + "config": { + "variables": [ + "{{variables.[Google Search Console Page]}}" + ], + "dataStream": { + "dataSourceConfig": { + "version": "2.0", + "tables": [ + { + "config": { + "variables": [ + "{{variables.[Google Search Console Page]}}" + ], + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "name": "pageDistribution", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Google Search Console Page]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Google Search Console Pages]}}" + } + }, + "id": "{{dataStreams.pageDistribution}}", + "pluginConfigId": "{{configId}}" + } + }, + "tableName": "dataset1" + } + ], + "sql": "SELECT\r\n Bucket,\r\n COUNT(*) AS Queries\r\nFROM dataset1\r\nGROUP BY Bucket\r\nORDER BY\r\nCASE Bucket\r\n WHEN '1-3' THEN 1\r\n WHEN '4-10' THEN 2\r\n WHEN '11-20' THEN 3\r\n WHEN '21-50' THEN 4\r\n ELSE 5\r\nEND" + }, + "id": "datastream-sql" + }, + "scope": { + "query": "g.V().has('id', within(ids_x17OQVG9BsPtxhZAiSKq))", + "bindings": { + "ids_x17OQVG9BsPtxhZAiSKq": [ + "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" + ] + }, + "queryDetail": { + "ids": [ + "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" + ] + } + }, + "_type": "tile/data-stream", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "title": "Ranking distribution", + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "color": { + "type": "default" + }, + "xAxisGroup": "none", + "showLegend": false, + "range": { + "type": "auto" + }, + "showGrid": true, + "grouping": false, + "displayMode": "actual", + "xAxisData": "Bucket", + "showTotals": false, + "yAxisLabel": "Queries", + "horizontalLayout": "horizontal", + "showValue": false, + "yAxisData": [ + "Queries" + ], + "showYAxisLabel": true, + "xAxisLabel": "Position range", + "legendPosition": "bottom", + "showXAxisLabel": true + } + } + } + } + }, + { + "static": false, + "w": 5, + "moved": false, + "h": 2, + "x": 9, + "y": 4, + "i": "1af01875-5df5-4d30-ae42-f5c7ab1b841e", + "z": 0, + "config": { + "variables": [ + "{{variables.[Google Search Console Page]}}" + ], + "dataStream": { + "dataSourceConfig": { + "version": "2.0", + "tables": [ + { + "config": { + "variables": [ + "{{variables.[Google Search Console Page]}}" + ], + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "name": "queriesByPage", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Google Search Console Page]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Google Search Console Pages]}}" + } + }, + "id": "{{dataStreams.queriesByPage}}", + "pluginConfigId": "{{configId}}" + } + }, + "tableName": "dataset1" + } + ], + "sql": "SELECT *\r\nFROM dataset1\r\nWHERE Impressions >= 10\r\nAND CTR < 2\r\nORDER BY Impressions DESC" + }, + "id": "datastream-sql" + }, + "scope": { + "query": "g.V().has('id', within(ids_ld2AmVYZkZ4TEH5rBCXD))", + "bindings": { + "ids_ld2AmVYZkZ4TEH5rBCXD": [ + "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" + ] + }, + "queryDetail": { + "ids": [ + "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" + ] + } + }, + "_type": "tile/data-stream", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "baseTile": "data-stream-base-tile", + "title": "Query opportunities", + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "columnOrder": [], + "resizedColumns": { + "columnWidths": { + "Impressions": 74, + "Query": 144, + "Clicks": 67, + "Position": 86 + } + }, + "hiddenColumns": [] + } + } + } + } + }, + { + "static": false, + "w": 5, + "moved": false, + "h": 2, + "x": 4, + "y": 4, + "i": "54de8574-a118-47ba-8bb9-b78ac2fd4cfd", + "z": 0, + "config": { + "variables": [ + "{{variables.[Google Search Console Page]}}" + ], + "dataStream": { + "name": "queriesByPage", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Google Search Console Page]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Google Search Console Pages]}}" + } + }, + "id": "{{dataStreams.queriesByPage}}", + "sort": { + "by": [ + [ + "Position", + "desc" + ], + [ + "Impressions", + "desc" + ] + ] + }, + "pluginConfigId": "{{configId}}" + }, + "_type": "tile/data-stream", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "baseTile": "data-stream-base-tile", + "title": "Top queries", + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "columnOrder": [ + "Query", + "Clicks", + "Impressions", + "CTR", + "Position" + ], + "resizedColumns": { + "columnWidths": { + "CTR": 74, + "Impressions": 83, + "Query": 142, + "Clicks": 93, + "Position": 81 + } + }, + "hiddenColumns": [] + } + } + } + } + }, + { + "x": 5, + "h": 2, + "i": "b2061d65-1500-4ec4-b9ea-296cf9cf4a97", + "y": 0, + "config": { + "variables": [ + "{{variables.[Google Search Console Page]}}" + ], + "dataStream": { + "name": "pagePerformanceOverTime", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Google Search Console Page]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Google Search Console Pages]}}" + } + }, + "id": "{{dataStreams.pagePerformanceOverTime}}", + "pluginConfigId": "{{configId}}" + }, + "_type": "tile/data-stream", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "title": "Page performance over time", + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "yAxisLabel": "Number", + "xAxisColumn": "Date", + "showLegend": true, + "seriesColumn": "none", + "xAxisLabel": "Date", + "legendPosition": "right", + "yAxisColumn": [ + "Clicks", + "Impressions", + "CTR" + ] + } + } + } + }, + "w": 9 + }, + { + "x": 5, + "h": 2, + "i": "52de2c7b-195d-41cf-97e8-a27997e9b501", + "y": 2, + "config": { + "variables": [ + "{{variables.[Google Search Console Page]}}" + ], + "dataStream": { + "name": "pagePerformanceOverTime", + "dataSourceConfig": { + "scope": { + "variable": "{{variables.[Google Search Console Page]}}", + "workspace": "{{workspaceId}}", + "scope": "{{scopes.[Google Search Console Pages]}}" + } + }, + "id": "{{dataStreams.pagePerformanceOverTime}}", + "pluginConfigId": "{{configId}}" + }, + "_type": "tile/data-stream", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "title": "Ranking over time", + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "seriesColumn": "none", + "yAxisLabel": "Position", + "xAxisLabel": "Date", + "xAxisColumn": "Date", + "yAxisColumn": [ + "Position" + ] + } + } + } + }, + "w": 9 + } + ], + "version": 593, + "columns": 14 + }, + "variables": [ + "{{variables.[Google Search Console Page]}}" + ], + "timeframe": "last30days" +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/defaultContent/scopes.json b/plugins/GoogleSearchConsole/v1/defaultContent/scopes.json new file mode 100644 index 00000000..b8bfcf23 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/defaultContent/scopes.json @@ -0,0 +1,19 @@ +[ + { + "name": "Google Search Console Pages", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "gsc-page" + ] + } + }, + "variable": { + "name": "Google Search Console Page", + "type": "object", + "default": "none", + "allowMultipleSelection": false + } + } +] \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json b/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json new file mode 100644 index 00000000..ac15049d --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json @@ -0,0 +1,398 @@ +{ + "name": "Site Overview", + "schemaVersion": "1.5", + "dashboard": { + "_type": "layout/grid", + "contents": [ + { + "static": false, + "w": 4, + "moved": false, + "h": 3, + "x": 8, + "y": 0, + "i": "abbfb7ce-6d8e-4347-9190-6274b9e5233d", + "z": 0, + "config": { + "dataStream": { + "name": "topQueries", + "metadata": [ + { + "shape": [ + "number", + { + "thousandsSeparator": true + } + ], + "name": "Position" + }, + { + "pattern": ".*" + } + ], + "id": "{{dataStreams.queries}}", + "pluginConfigId": "{{configId}}" + }, + "_type": "tile/data-stream", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "baseTile": "data-stream-base-tile", + "title": "Top queries", + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "columnOrder": [ + "Query", + "Impressions", + "Clicks", + "CTR", + "Position" + ], + "resizedColumns": { + "columnWidths": { + "Query": 192, + "Impressions": 69, + "Position": 82 + } + }, + "hiddenColumns": [] + } + } + } + } + }, + { + "static": false, + "w": 3, + "moved": false, + "h": 1, + "x": 0, + "y": 0, + "i": "874f5aad-220b-4e7f-8c62-376d969d2b8f", + "z": 0, + "config": { + "dataStream": { + "name": "siteSummary", + "id": "{{dataStreams.sitePerformanceSummary}}", + "pluginConfigId": "{{configId}}" + }, + "_type": "tile/data-stream", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "baseTile": "data-stream-base-tile", + "title": "Site summary", + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "columnOrder": [ + "Impressions", + "Clicks", + "CTR", + "Position" + ], + "resizedColumns": { + "columnWidths": { + "CTR": 69, + "Clicks": 83, + "Impressions": 109 + } + }, + "hiddenColumns": [] + } + } + } + } + }, + { + "static": false, + "w": 5, + "moved": false, + "h": 1, + "x": 3, + "y": 0, + "i": "03c9a833-b7aa-46a4-a811-6b7fb8f3754d", + "z": 0, + "config": { + "dataStream": { + "dataSourceConfig": { + "version": "2.0", + "tables": [ + { + "config": { + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "name": "previousPeriodPerformanceOverTime", + "id": "{{dataStreams.previousPeriodPerformanceOverTime}}", + "pluginConfigId": "{{configId}}" + } + }, + "tableName": "dataset1" + }, + { + "config": { + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "name": "sitePerformanceOverTime", + "id": "{{dataStreams.sitePerformanceOverTime}}", + "pluginConfigId": "{{configId}}" + } + }, + "tableName": "dataset2" + } + ], + "sql": "WITH current_period AS (\r\n SELECT\r\n SUM(Clicks) AS Clicks,\r\n SUM(Impressions) AS Impressions,\r\n SUM(Clicks) / NULLIF(SUM(Impressions), 0) * 100 AS CTR,\r\n AVG(Position) AS Position\r\n FROM dataset1\r\n),\r\n\r\nprevious_period AS (\r\n SELECT\r\n SUM(Clicks) AS Clicks,\r\n SUM(Impressions) AS Impressions,\r\n SUM(Clicks) / NULLIF(SUM(Impressions), 0) * 100 AS CTR,\r\n AVG(Position) AS Position\r\n FROM dataset2\r\n)\r\n\r\nSELECT\r\n ROUND(((current_period.Clicks - previous_period.Clicks) / NULLIF(previous_period.Clicks, 0)) * 100, 2) AS \"Clicks Change %\",\r\n\r\n ROUND(((current_period.Impressions - previous_period.Impressions) / NULLIF(previous_period.Impressions, 0)) * 100, 2) AS \"Impressions Change %\",\r\n\r\n ROUND(((current_period.CTR - previous_period.CTR) / NULLIF(previous_period.CTR, 0)) * 100, 2) AS \"CTR Change %\",\r\n\r\n ROUND(previous_period.Position - current_period.Position, 2) AS \"Position Change\"\r\n\r\nFROM current_period\r\nCROSS JOIN previous_period" + }, + "id": "datastream-sql" + }, + "scope": { + "query": "g.V().has('id', within(ids_CJ7tYgjdolxSg53jHrjr))", + "bindings": { + "ids_CJ7tYgjdolxSg53jHrjr": [ + "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" + ] + }, + "queryDetail": { + "ids": [ + "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" + ] + } + }, + "_type": "tile/data-stream", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "baseTile": "data-stream-base-tile", + "title": "Organic Search Performance", + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "columnOrder": [ + "Clicks Change %", + "Impressions Change %", + "CTR Change %", + "Position Change" + ], + "resizedColumns": { + "columnWidths": { + "Position Improvement": 137, + "Impressions Change %": 167, + "CTR Change %": 143, + "Clicks Change %": 165 + } + }, + "hiddenColumns": [] + } + } + } + } + }, + { + "static": false, + "w": 8, + "moved": false, + "h": 3, + "x": 0, + "y": 1, + "i": "55e0fd89-3712-4533-8550-022658189aa0", + "z": 0, + "config": { + "dataStream": { + "name": "sitePerformanceOverTime", + "id": "{{dataStreams.sitePerformanceOverTime}}", + "pluginConfigId": "{{configId}}" + }, + "_type": "tile/data-stream", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "title": "Site performance over time", + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "showLegend": true, + "seriesColumn": "none", + "legendPosition": "bottom", + "xAxisColumn": "Date", + "yAxisColumn": [ + "CTR", + "Clicks", + "Impressions", + "Position" + ] + } + } + } + } + }, + { + "static": false, + "w": 4, + "moved": false, + "h": 3, + "x": 8, + "y": 3, + "i": "8ff8253a-29a0-4fa5-b7e1-13f6d2551951", + "z": 0, + "config": { + "dataStream": { + "name": "topPages", + "id": "{{dataStreams.pages}}", + "pluginConfigId": "{{configId}}" + }, + "_type": "tile/data-stream", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "baseTile": "data-stream-base-tile", + "title": "Top pages", + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "columnOrder": [ + "Page", + "Clicks", + "Impressions", + "CTR", + "Position" + ], + "resizedColumns": { + "columnWidths": { + "Position": 85, + "Impressions": 110, + "Page": 130 + } + }, + "hiddenColumns": [] + } + } + } + } + }, + { + "static": false, + "w": 4, + "moved": false, + "h": 2, + "x": 4, + "y": 4, + "i": "c8648379-8e3c-4341-af14-6930f75ba24f", + "z": 0, + "config": { + "dataStream": { + "name": "countryBreakdown", + "id": "{{dataStreams.countryBreakdown}}", + "sort": { + "by": [ + [ + "Clicks", + "desc" + ], + [ + "Impressions", + "desc" + ] + ] + }, + "pluginConfigId": "{{configId}}" + }, + "_type": "tile/data-stream", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "title": "Country breakdown", + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "columnOrder": [ + "Country", + "Clicks", + "Impressions", + "CTR", + "Position" + ], + "hiddenColumns": [] + } + } + } + } + }, + { + "static": false, + "w": 4, + "moved": false, + "h": 2, + "x": 0, + "y": 4, + "i": "be8d0a39-4442-48c1-a8e7-0b3af34845eb", + "z": 0, + "config": { + "dataStream": { + "name": "deviceBreakdown", + "id": "{{dataStreams.deviceBreakdown}}", + "pluginConfigId": "{{configId}}" + }, + "_type": "tile/data-stream", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "title": "Device breakdown", + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "color": { + "type": "default" + }, + "xAxisGroup": "none", + "showLegend": true, + "range": { + "type": "auto" + }, + "showGrid": true, + "grouping": false, + "displayMode": "actual", + "xAxisData": "Device", + "showTotals": false, + "yAxisLabel": "", + "horizontalLayout": "horizontal", + "showValue": false, + "yAxisData": [ + "Clicks", + "Impressions", + "Position", + "CTR" + ], + "showYAxisLabel": true, + "xAxisLabel": "", + "legendPosition": "bottom", + "showXAxisLabel": true + } + } + } + } + } + ], + "version": 266, + "columns": 12 + }, + "timeframe": "last30days" +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/docs/README.md b/plugins/GoogleSearchConsole/v1/docs/README.md new file mode 100644 index 00000000..61407cc0 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/docs/README.md @@ -0,0 +1,95 @@ +# Before you start + +## Prerequisites + +- A Google account with access to Google Search Console +- A verified URL-prefix property in Google Search Console +- A Google Cloud Project + +## Enabling the Google Search Console API + +1. Go to the [Google Cloud Console](https://console.cloud.google.com/) + +2. Select the project you wish to use + +3. Navigate to **APIs & Services** > **Library** + +4. Search for **Google Search Console API** + +5. Select it and click **Enable** + +## Creating OAuth 2.0 Credentials + +1. From the [Google Cloud Console](https://console.cloud.google.com/), navigate to **APIs & Services** > **Credentials** + +2. Click **+ Create credentials** and select **OAuth client ID** + +3. If prompted, configure the OAuth consent screen: + - Choose **External** + - Enter the required application details + - Add the following scope: + ``` + https://www.googleapis.com/auth/webmasters.readonly + ``` + +4. On the **Create OAuth client ID** page: + - Select **Web application** as the application type + - Enter a name for your OAuth client + +5. Add authorized JavaScript origins: + - Click **+ Add URI** under **Authorized JavaScript origins** + - Enter: + ``` + https://app.squaredup.com + ``` + +6. Add authorized redirect URIs: + - Click **+ Add URI** under **Authorized redirect URIs** + - Enter: + ``` + https://app.squaredup.com/settings/pluginsoauth2 + ``` + +7. Click **Create** + +8. Copy the **Client ID** and **Client Secret** that are displayed, save these somewhere secure as you won't be able to view the client secret again + +## Configuring the plugin + +Populate the following fields when configuring the plugin: + +| Field | Description | +|---------|---------| +| Search Console property URL | The exact URL-prefix property from Google Search Console (for example, `https://example.com/`) | +| Google OAuth client ID | The Client ID created in Google Cloud | +| Google OAuth client secret | The Client Secret created in Google Cloud | +| Sign in | Click to authenticate using a Google account that has access to the Search Console property | + +## Example configuration + +| Setting | Example | +|---------|---------| +| Search Console property URL | `https://example.com/` | +| Google OAuth client ID | `1234567890-example.apps.googleusercontent.com` | +| Google OAuth client secret | `GOCSPX-xxxxxxxxxxxxxxxxxxxx` | + +## Troubleshooting + +### Authentication fails + +Verify that: + +- The Google Search Console API is enabled +- The Client ID and Client Secret are correct +- The redirect URI exactly matches: + ``` + https://app.squaredup.com/settings/pluginsoauth2 + ``` + +### Property not found + +Verify that: + +- The property exists in Google Search Console +- The signed-in Google account has access to the property +- The property URL exactly matches the URL entered in the plugin configuration \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/icon.svg b/plugins/GoogleSearchConsole/v1/icon.svg new file mode 100644 index 00000000..fc5a0504 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/indexDefinitions/default.json b/plugins/GoogleSearchConsole/v1/indexDefinitions/default.json new file mode 100644 index 00000000..af67b519 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/indexDefinitions/default.json @@ -0,0 +1,19 @@ +{ + "steps": [ + { + "name": "Import pages", + "dataStream": { + "name": "pageUrLs", + "config": {} + }, + "timeframe": "none", + "objectMapping": { + "id": "value", + "name": "label", + "type": { + "value": "gsc-page" + } + } + } + ] +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/metadata.json b/plugins/GoogleSearchConsole/v1/metadata.json new file mode 100644 index 00000000..f4cdb473 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/metadata.json @@ -0,0 +1,42 @@ +{ + "name": "google-search-console", + "displayName": "Google Search Console", + "version": "1.0.0", + "author": { + "name": "Daniel.Hodgson@squaredup.com", + "type": "community" + }, + "description": "Monitor performance metrics for a GSC property", + "category": "Analytics", + "type": "hybrid", + "schemaVersion": "2.0", + "base": { + "plugin": "WebAPI", + "majorVersion": "1", + "config": { + "queryArgs": [], + "headers": [], + "oauth2TokenExtraArgs": [], + "oauth2ClientSecret": "{{oauth2ClientSecret}}", + "oauth2ClientSecretLocationDuringAuth": "body", + "oauth2AuthUrl": "https://accounts.google.com/o/oauth2/v2/auth", + "authMode": "oauth2", + "oauth2GrantType": "authCode", + "baseUrl": "https://www.googleapis.com/webmasters/v3/sites/{{encodeURIComponent(siteUrl)}}/searchAnalytics/query", + "oauth2TokenExtraHeaders": [], + "oauth2ClientId": "{{oauth2ClientId}}", + "oauth2TokenUrl": "https://oauth2.googleapis.com/token", + "oauth2AuthExtraArgs": [ + { + "value": "offline", + "key": "access_type" + }, + { + "value": "consent", + "key": "prompt" + } + ], + "oauth2Scope": "https://www.googleapis.com/auth/webmasters.readonly" + } + } +} \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/ui.json b/plugins/GoogleSearchConsole/v1/ui.json new file mode 100644 index 00000000..5db699c3 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/ui.json @@ -0,0 +1,39 @@ +[ + { + "name": "siteUrl", + "type": "text", + "label": "Search Console property URL", + "description": "Enter the exact URL-prefix property from Google Search Console. Example: https://example.com/", + "placeholder": "https://example.com/", + "validation": { + "required": true + } + }, + { + "name": "oauth2ClientId", + "type": "text", + "label": "Google OAuth client ID", + "description": "Enter the OAuth client ID from your Google Cloud project.", + "placeholder": "1234567890-example.apps.googleusercontent.com", + "validation": { + "required": true + } + }, + { + "name": "oauth2ClientSecret", + "type": "password", + "label": "Google OAuth client secret", + "description": "Enter the OAuth client secret from your Google Cloud project.", + "validation": { + "required": true + } + }, + { + "type": "oAuth2", + "name": "oauth2AuthCodeSignIn", + "label": "Sign in with Google Search Console", + "validation": { + "required": true + } + } +] \ No newline at end of file From 122f20c7223e691969969c814d11638243c96274 Mon Sep 17 00:00:00 2001 From: Dan H Date: Fri, 19 Jun 2026 14:40:55 +0100 Subject: [PATCH 2/9] Fixed the incorrect binding of dataset1 and dataset2 in the SQL for the "Biggest Ranking Changes" tile of the "Page Overview" dashboard --- .../v1/defaultContent/pageOverview.dash.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json b/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json index 577bf7eb..e8d4e513 100644 --- a/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json +++ b/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json @@ -238,7 +238,7 @@ "tableName": "dataset2" } ], - "sql": "SELECT\r\n c.Query,\r\n ROUND(p.Position - c.Position, 1) AS PositionChange,\r\n c.Position AS CurrentPosition,\r\n p.Position AS PreviousPosition,\r\n c.Clicks,\r\n c.Impressions\r\nFROM dataset1 c\r\nINNER JOIN dataset2 p\r\n ON c.Query = p.Query\r\nWHERE\r\n c.Impressions > 0\r\n OR p.Impressions > 0\r\nORDER BY PositionChange DESC\r\nLIMIT 10" + "sql": "SELECT\r\n c.Query,\r\n ROUND(p.Position - c.Position, 1) AS PositionChange,\r\n c.Position AS CurrentPosition,\r\n p.Position AS PreviousPosition,\r\n c.Clicks,\r\n c.Impressions\r\nFROM dataset2 c\r\nINNER JOIN dataset1 p\r\n ON c.Query = p.Query\r\nWHERE\r\n c.Impressions > 0\r\n OR p.Impressions > 0\r\nORDER BY PositionChange DESC\r\nLIMIT 10" }, "id": "datastream-sql" }, From 677fbfff2b4dd2cc55df211c704f25ffb99acc08 Mon Sep 17 00:00:00 2001 From: Dan H Date: Fri, 19 Jun 2026 14:49:41 +0100 Subject: [PATCH 3/9] Fixed the incorrect binding of dataset1 and dataset2 in the SQL for the "Organic Search Performance " tile of the "Site Overview" dashboard --- .../v1/defaultContent/siteOverview.dash.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json b/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json index ac15049d..5b9bc874 100644 --- a/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json +++ b/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json @@ -150,7 +150,7 @@ "tableName": "dataset2" } ], - "sql": "WITH current_period AS (\r\n SELECT\r\n SUM(Clicks) AS Clicks,\r\n SUM(Impressions) AS Impressions,\r\n SUM(Clicks) / NULLIF(SUM(Impressions), 0) * 100 AS CTR,\r\n AVG(Position) AS Position\r\n FROM dataset1\r\n),\r\n\r\nprevious_period AS (\r\n SELECT\r\n SUM(Clicks) AS Clicks,\r\n SUM(Impressions) AS Impressions,\r\n SUM(Clicks) / NULLIF(SUM(Impressions), 0) * 100 AS CTR,\r\n AVG(Position) AS Position\r\n FROM dataset2\r\n)\r\n\r\nSELECT\r\n ROUND(((current_period.Clicks - previous_period.Clicks) / NULLIF(previous_period.Clicks, 0)) * 100, 2) AS \"Clicks Change %\",\r\n\r\n ROUND(((current_period.Impressions - previous_period.Impressions) / NULLIF(previous_period.Impressions, 0)) * 100, 2) AS \"Impressions Change %\",\r\n\r\n ROUND(((current_period.CTR - previous_period.CTR) / NULLIF(previous_period.CTR, 0)) * 100, 2) AS \"CTR Change %\",\r\n\r\n ROUND(previous_period.Position - current_period.Position, 2) AS \"Position Change\"\r\n\r\nFROM current_period\r\nCROSS JOIN previous_period" + "sql": "WITH current_period AS (\r\n SELECT\r\n SUM(Clicks) AS Clicks,\r\n SUM(Impressions) AS Impressions,\r\n SUM(Clicks) / NULLIF(SUM(Impressions), 0) * 100 AS CTR,\r\n AVG(Position) AS Position\r\n FROM dataset2\r\n),\r\n\r\nprevious_period AS (\r\n SELECT\r\n SUM(Clicks) AS Clicks,\r\n SUM(Impressions) AS Impressions,\r\n SUM(Clicks) / NULLIF(SUM(Impressions), 0) * 100 AS CTR,\r\n AVG(Position) AS Position\r\n FROM dataset1\r\n)\r\n\r\nSELECT\r\n ROUND(((current_period.Clicks - previous_period.Clicks) / NULLIF(previous_period.Clicks, 0)) * 100, 2) AS \"Clicks Change %\",\r\n\r\n ROUND(((current_period.Impressions - previous_period.Impressions) / NULLIF(previous_period.Impressions, 0)) * 100, 2) AS \"Impressions Change %\",\r\n\r\n ROUND(((current_period.CTR - previous_period.CTR) / NULLIF(previous_period.CTR, 0)) * 100, 2) AS \"CTR Change %\",\r\n\r\n ROUND(previous_period.Position - current_period.Position, 2) AS \"Position Change\"\r\n\r\nFROM current_period\r\nCROSS JOIN previous_period" }, "id": "datastream-sql" }, From ef0bde48b9e0384e8ad66b178eb6bc13083f7046 Mon Sep 17 00:00:00 2001 From: Dan H Date: Wed, 24 Jun 2026 09:17:33 +0100 Subject: [PATCH 4/9] Addressed PR feedback and review comments: Fixed inverted datasets Fixed typos Updated CTR shape to be handled by SquaredUp metadata Renamed Organic search performance tiles to "Period performance change" Added tags to data streams Updated author to use GitHub handle --- .../v1/dataStreams/countryBreakdown.json | 26 +++- .../v1/dataStreams/deviceBreakdown.json | 26 +++- .../v1/dataStreams/pageDistribution.json | 5 +- .../dataStreams/pagePerformanceOverTime.json | 27 +++- .../dataStreams/pagePerformanceSummary.json | 29 +++-- .../v1/dataStreams/pageUrLs.json | 6 +- .../v1/dataStreams/pages.json | 26 +++- .../previousPeriodPagePerformance.json | 120 ++++++++++-------- .../previousPeriodPerformanceOverTime.json | 70 ++++++---- .../previousPeriodQueriesByPage.json | 120 ++++++++++-------- .../v1/dataStreams/queries.json | 28 +++- .../v1/dataStreams/queriesByPage.json | 29 +++-- .../scripts/postRequest/countryBreakdown.js | 8 +- .../scripts/postRequest/deviceBreakdown.js | 8 +- .../postRequest/pagePerformanceOverTime.js | 4 +- .../postRequest/pagePerformanceSummary.js | 9 ++ .../dataStreams/scripts/postRequest/pages.js | 14 +- .../previousPeriodPerformanceOverTime.js | 8 +- .../previousPeriodQueriesByPage.js | 14 +- .../scripts/postRequest/queries.js | 11 ++ .../scripts/postRequest/script1.js | 9 -- .../scripts/postRequest/script2.js | 11 -- .../postRequest/sitePerformanceOverTime.js | 8 +- .../postRequest/sitePerformanceSummary.js | 14 +- .../dataStreams/sitePerformanceOverTime.json | 24 +++- .../dataStreams/sitePerformanceSummary.json | 20 ++- .../v1/defaultContent/pageOverview.dash.json | 2 +- .../v1/defaultContent/siteOverview.dash.json | 2 +- plugins/GoogleSearchConsole/v1/metadata.json | 2 +- 29 files changed, 426 insertions(+), 254 deletions(-) create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pagePerformanceSummary.js create mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/queries.js delete mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script1.js delete mode 100644 plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script2.js diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/countryBreakdown.json b/plugins/GoogleSearchConsole/v1/dataStreams/countryBreakdown.json index ccb05ad9..6920314b 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/countryBreakdown.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/countryBreakdown.json @@ -15,17 +15,31 @@ "postBody": { "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", - "dimensions": [ - "country" - ], - "rowLimit": 25000, + "dimensions": ["country"], + "rowLimit": 2500, "dataState": "final" }, "postRequestScript": "postRequest/countryBreakdown.js", "getArgs": [], "headers": [] }, + "metadata": [ + { + "shape": [ + "percent", + { + "thousandsSeparator": true, + "decimalPlaces": 2, + "asZeroToOne": true + } + ], + "name": "CTR" + }, + { + "pattern": ".*" + } + ], "providesPluginDiagnostics": true, "timeframes": true, - "tags": [] -} \ No newline at end of file + "tags": ["SEO", "Analytics"] +} diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/deviceBreakdown.json b/plugins/GoogleSearchConsole/v1/dataStreams/deviceBreakdown.json index 93b605a8..2e93f7ca 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/deviceBreakdown.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/deviceBreakdown.json @@ -15,17 +15,31 @@ "postBody": { "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", - "dimensions": [ - "device" - ], - "rowLimit": 25000, + "dimensions": ["device"], + "rowLimit": 2500, "dataState": "final" }, "postRequestScript": "postRequest/deviceBreakdown.js", "getArgs": [], "headers": [] }, + "metadata": [ + { + "shape": [ + "percent", + { + "thousandsSeparator": true, + "decimalPlaces": 2, + "asZeroToOne": true + } + ], + "name": "CTR" + }, + { + "pattern": ".*" + } + ], "providesPluginDiagnostics": true, "timeframes": true, - "tags": [] -} \ No newline at end of file + "tags": ["SEO", "Analytics"] +} diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/pageDistribution.json b/plugins/GoogleSearchConsole/v1/dataStreams/pageDistribution.json index 2d118eda..6b6cd57b 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/pageDistribution.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/pageDistribution.json @@ -31,14 +31,13 @@ ] } ], - "rowLimit": 25000 + "rowLimit": 2500 }, "postRequestScript": "postRequest/pageDistribution.js" }, "providesPluginDiagnostics": true, "timeframes": true, - "tags": [], - + "tags": ["SEO", "Analytics"], "ui": [ { "name": "scope", diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceOverTime.json b/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceOverTime.json index 6d93f5d8..ef3f040b 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceOverTime.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceOverTime.json @@ -15,9 +15,7 @@ "postBody": { "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", - "dimensions": [ - "date" - ], + "dimensions": ["date"], "dimensionFilterGroups": [ { "filters": [ @@ -29,7 +27,7 @@ ] } ], - "rowLimit": 25000 + "rowLimit": 2500 }, "postRequestScript": "postRequest/pagePerformanceOverTime.js", "getArgs": [], @@ -37,8 +35,23 @@ }, "providesPluginDiagnostics": true, "timeframes": true, - "tags": [], - + "tags": ["SEO", "Analytics"], + "metadata": [ + { + "shape": [ + "percent", + { + "thousandsSeparator": true, + "decimalPlaces": 2, + "asZeroToOne": true + } + ], + "name": "CTR" + }, + { + "pattern": ".*" + } + ], "ui": [ { "name": "scope", @@ -56,4 +69,4 @@ } } ] -} \ No newline at end of file +} diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceSummary.json b/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceSummary.json index 675ddf7f..26347973 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceSummary.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceSummary.json @@ -17,9 +17,7 @@ "postBody": { "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", - "dimensions": [ - "page" - ], + "dimensions": ["page"], "dimensionFilterGroups": [ { "filters": [ @@ -31,14 +29,29 @@ ] } ], - "rowLimit": 25000 + "rowLimit": 2500 }, - "postRequestScript": "postRequest/script1.js" + "postRequestScript": "postRequest/pagePerformanceSummary.js" }, "providesPluginDiagnostics": true, "timeframes": true, - "tags": [], - + "tags": ["SEO", "Analytics"], + "metadata": [ + { + "shape": [ + "percent", + { + "thousandsSeparator": true, + "decimalPlaces": 2, + "asZeroToOne": true + } + ], + "name": "CTR" + }, + { + "pattern": ".*" + } + ], "ui": [ { "name": "scope", @@ -56,4 +69,4 @@ } } ] -} \ No newline at end of file +} diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/pageUrLs.json b/plugins/GoogleSearchConsole/v1/dataStreams/pageUrLs.json index e4a5de8e..ee8fd342 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/pageUrLs.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/pageUrLs.json @@ -1,7 +1,7 @@ { "name": "pageUrLs", "displayName": "Page URLs", - "description": "Returns a list off URLs with impressions in the last year", + "description": "Returns a list of URLs with impressions in the last year", "baseDataSourceName": "httpRequestUnscoped", "config": { "httpMethod": "post", @@ -18,7 +18,7 @@ "dimensions": [ "page" ], - "rowLimit": 25 + "rowLimit": 5000 }, "postRequestScript": "postRequest/pageUrLs.js", "getArgs": [], @@ -26,5 +26,5 @@ }, "timeframes": false, "providesPluginDiagnostics": true, - "tags": [] + "tags": ["SEO", "Analytics"] } \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/pages.json b/plugins/GoogleSearchConsole/v1/dataStreams/pages.json index 0993d17f..018149d9 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/pages.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/pages.json @@ -15,16 +15,30 @@ "postBody": { "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", - "dimensions": [ - "page" - ], - "rowLimit": 25000 + "dimensions": ["page"], + "rowLimit": 5000 }, "postRequestScript": "postRequest/pages.js", "getArgs": [], "headers": [] }, + "metadata": [ + { + "shape": [ + "percent", + { + "thousandsSeparator": true, + "decimalPlaces": 2, + "asZeroToOne": true + } + ], + "name": "CTR" + }, + { + "pattern": ".*" + } + ], "providesPluginDiagnostics": true, "timeframes": true, - "tags": [] -} \ No newline at end of file + "tags": ["SEO", "Analytics"] +} diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPagePerformance.json b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPagePerformance.json index 9ffed41f..e734f799 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPagePerformance.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPagePerformance.json @@ -1,59 +1,75 @@ { - "name": "previousPeriodPagePerformance", - "displayName": "Previous period page performance", - "description": "Returns a summary of performance for the previous period of a given timeframe for the selected page", - "baseDataSourceName": "httpRequestUnscoped", - "config": { - "httpMethod": "post", - "errorHandling": { - "type": "default" + "name": "previousPeriodPagePerformance", + "displayName": "Previous period page performance", + "description": "Returns a summary of performance for the previous period of a given timeframe for the selected page", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "getArgs": [], + "headers": [], + "postBody": { + "startDate": "{{new Date(new Date(timeframe.start).getTime() - (new Date(timeframe.end).getTime() - new Date(timeframe.start).getTime()) - 86400000).toISOString().split('T')[0]}}", + "endDate": "{{new Date(new Date(timeframe.start).getTime() - 86400000).toISOString().split('T')[0]}}", + "dimensions": ["page"], + "dimensionFilterGroups": [ + { + "filters": [ + { + "dimension": "page", + "operator": "equals", + "expression": "{{scope?.[0]?.name}}" + } + ] + } + ], + "rowLimit": 25000 + }, + "postRequestScript": "postRequest/pagePerformanceSummary.js" }, - "paging": { - "mode": "none" - }, - "expandInnerObjects": true, - "getArgs": [], - "headers": [], - "postBody": { - "startDate": "{{new Date(new Date(timeframe.start).getTime() - (new Date(timeframe.end).getTime() - new Date(timeframe.start).getTime()) - 86400000).toISOString().split('T')[0]}}", - "endDate": "{{new Date(new Date(timeframe.start).getTime() - 86400000).toISOString().split('T')[0]}}", - "dimensions": ["page"], - "dimensionFilterGroups": [ + "metadata": [ { - "filters": [ - { - "dimension": "page", - "operator": "equals", - "expression": "{{scope?.[0]?.name}}" - } - ] + "shape": [ + "percent", + { + "thousandsSeparator": true, + "decimalPlaces": 2, + "asZeroToOne": true + } + ], + "name": "CTR" + }, + { + "pattern": ".*" } - ], - "rowLimit": 25000 + ], + "timeframes": true, + "providesPluginDiagnostics": true, + "tags": ["SEO", "Analytics"], + "visibility": { + "type": "hidden" }, - "postRequestScript": "postRequest/script1.js" - }, - "timeframes": true, - "providesPluginDiagnostics": true, - "tags": [], - "visibility": { - "type": "hidden" - }, - "ui": [ - { - "name": "scope", - "objectLimit": 1, - "label": "Scope", - "type": "objects", - "matches": { - "sourceType": { - "type": "equals", - "value": "gsc-page" + "ui": [ + { + "name": "scope", + "objectLimit": 1, + "label": "Scope", + "type": "objects", + "matches": { + "sourceType": { + "type": "equals", + "value": "gsc-page" + } + }, + "validation": { + "required": true + } } - }, - "validation": { - "required": true - } - } - ] + ] } diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPerformanceOverTime.json b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPerformanceOverTime.json index 63f862a7..0125e6dd 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPerformanceOverTime.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPerformanceOverTime.json @@ -1,31 +1,47 @@ { - "name": "previousPeriodPerformanceOverTime", - "displayName": "Previous period performance over time", - "description": "Returns daily performance for the previous period of a given timeframe for the selected page", - "baseDataSourceName": "httpRequestUnscoped", - "visibility": { - "type": "hidden" - }, - "config": { - "httpMethod": "post", - "errorHandling": { - "type": "default" + "name": "previousPeriodPerformanceOverTime", + "displayName": "Previous period performance over time", + "description": "Returns daily performance for the previous period of a given timeframe for the selected page", + "baseDataSourceName": "httpRequestUnscoped", + "visibility": { + "type": "hidden" }, - "paging": { - "mode": "none" + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "postBody": { + "startDate": "{{new Date(new Date(timeframe.start).getTime() - (new Date(timeframe.end).getTime() - new Date(timeframe.start).getTime()) - 86400000).toISOString().split('T')[0]}}", + "endDate": "{{new Date(new Date(timeframe.start).getTime() - 86400000).toISOString().split('T')[0]}}", + "dimensions": ["date"], + "rowLimit": 25000 + }, + "postRequestScript": "postRequest/previousPeriodPerformanceOverTime.js", + "getArgs": [], + "headers": [] }, - "expandInnerObjects": true, - "postBody": { - "startDate": "{{new Date(new Date(timeframe.start).getTime() - (new Date(timeframe.end).getTime() - new Date(timeframe.start).getTime()) - 86400000).toISOString().split('T')[0]}}", - "endDate": "{{new Date(new Date(timeframe.start).getTime() - 86400000).toISOString().split('T')[0]}}", - "dimensions": ["date"], - "rowLimit": 25000 - }, - "postRequestScript": "postRequest/previousPeriodPerformanceOverTime.js", - "getArgs": [], - "headers": [] - }, - "timeframes": true, - "providesPluginDiagnostics": true, - "tags": [] + "metadata": [ + { + "shape": [ + "percent", + { + "thousandsSeparator": true, + "decimalPlaces": 2, + "asZeroToOne": true + } + ], + "name": "CTR" + }, + { + "pattern": ".*" + } + ], + "timeframes": true, + "providesPluginDiagnostics": true, + "tags": ["SEO", "Analytics"] } diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodQueriesByPage.json b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodQueriesByPage.json index b029a1f3..0115841d 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodQueriesByPage.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodQueriesByPage.json @@ -1,59 +1,75 @@ { - "name": "previousPeriodQueriesByPage", - "displayName": "Previous period queries by page", - "description": "Returns queries for the previous period of a given timeframe for the selected page", - "baseDataSourceName": "httpRequestUnscoped", - "config": { - "httpMethod": "post", - "errorHandling": { - "type": "default" + "name": "previousPeriodQueriesByPage", + "displayName": "Previous period queries by page", + "description": "Returns queries for the previous period of a given timeframe for the selected page", + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "post", + "errorHandling": { + "type": "default" + }, + "paging": { + "mode": "none" + }, + "expandInnerObjects": true, + "getArgs": [], + "headers": [], + "postBody": { + "startDate": "{{new Date(new Date(timeframe.start).getTime() - (new Date(timeframe.end).getTime() - new Date(timeframe.start).getTime()) - 86400000).toISOString().split('T')[0]}}", + "endDate": "{{new Date(new Date(timeframe.start).getTime() - 86400000).toISOString().split('T')[0]}}", + "dimensions": ["query"], + "dimensionFilterGroups": [ + { + "filters": [ + { + "dimension": "page", + "operator": "equals", + "expression": "{{scope?.[0]?.name}}" + } + ] + } + ], + "rowLimit": 2500 + }, + "postRequestScript": "postRequest/previousPeriodQueriesByPage.js" }, - "paging": { - "mode": "none" - }, - "expandInnerObjects": true, - "getArgs": [], - "headers": [], - "postBody": { - "startDate": "{{new Date(new Date(timeframe.start).getTime() - (new Date(timeframe.end).getTime() - new Date(timeframe.start).getTime()) - 86400000).toISOString().split('T')[0]}}", - "endDate": "{{new Date(new Date(timeframe.start).getTime() - 86400000).toISOString().split('T')[0]}}", - "dimensions": ["query"], - "dimensionFilterGroups": [ + "metadata": [ { - "filters": [ - { - "dimension": "page", - "operator": "equals", - "expression": "{{scope?.[0]?.name}}" - } - ] + "shape": [ + "percent", + { + "thousandsSeparator": true, + "decimalPlaces": 2, + "asZeroToOne": true + } + ], + "name": "CTR" + }, + { + "pattern": ".*" } - ], - "rowLimit": 25000 + ], + "timeframes": true, + "providesPluginDiagnostics": true, + "tags": ["SEO", "Analytics"], + "visibility": { + "type": "hidden" }, - "postRequestScript": "postRequest/previousPeriodQueriesByPage.js" - }, - "timeframes": true, - "providesPluginDiagnostics": true, - "tags": [], - "visibility": { - "type": "hidden" - }, - "ui": [ - { - "name": "scope", - "objectLimit": 1, - "label": "Scope", - "type": "objects", - "matches": { - "sourceType": { - "type": "equals", - "value": "gsc-page" + "ui": [ + { + "name": "scope", + "objectLimit": 1, + "label": "Scope", + "type": "objects", + "matches": { + "sourceType": { + "type": "equals", + "value": "gsc-page" + } + }, + "validation": { + "required": true + } } - }, - "validation": { - "required": true - } - } - ] + ] } diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/queries.json b/plugins/GoogleSearchConsole/v1/dataStreams/queries.json index 8eb1b87e..5aa25680 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/queries.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/queries.json @@ -15,17 +15,31 @@ "postBody": { "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", - "dimensions": [ - "query" - ], - "rowLimit": 25000, + "dimensions": ["query"], + "rowLimit": 2500, "dataState": "final" }, - "postRequestScript": "postRequest/script2.js", + "postRequestScript": "postRequest/queries.js", "getArgs": [], "headers": [] }, + "metadata": [ + { + "shape": [ + "percent", + { + "thousandsSeparator": true, + "decimalPlaces": 2, + "asZeroToOne": true + } + ], + "name": "CTR" + }, + { + "pattern": ".*" + } + ], "providesPluginDiagnostics": true, "timeframes": true, - "tags": [] -} \ No newline at end of file + "tags": ["SEO", "Analytics"] +} diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/queriesByPage.json b/plugins/GoogleSearchConsole/v1/dataStreams/queriesByPage.json index a296ede9..66c8b3a1 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/queriesByPage.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/queriesByPage.json @@ -15,9 +15,7 @@ "postBody": { "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", - "dimensions": [ - "query" - ], + "dimensions": ["query"], "dimensionFilterGroups": [ { "filters": [ @@ -29,17 +27,32 @@ ] } ], - "rowLimit": 25000, + "rowLimit": 2500, "dataState": "final" }, - "postRequestScript": "postRequest/script2.js", + "postRequestScript": "postRequest/queries.js", "getArgs": [], "headers": [] }, "providesPluginDiagnostics": true, "timeframes": true, - "tags": [], - + "tags": ["SEO", "Analytics"], + "metadata": [ + { + "shape": [ + "percent", + { + "thousandsSeparator": true, + "decimalPlaces": 2, + "asZeroToOne": true + } + ], + "name": "CTR" + }, + { + "pattern": ".*" + } + ], "ui": [ { "name": "scope", @@ -57,4 +70,4 @@ } } ] -} \ No newline at end of file +} diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/countryBreakdown.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/countryBreakdown.js index e573e04f..dc5f6b1f 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/countryBreakdown.js +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/countryBreakdown.js @@ -1,9 +1,9 @@ const rows = data.rows ?? []; -result = rows.map(row => ({ +result = rows.map((row) => ({ Country: row.keys?.[0], Clicks: row.clicks, Impressions: row.impressions, - CTR: Number((row.ctr * 100).toFixed(2)), - Position: Number(row.position.toFixed(2)) -})); \ No newline at end of file + CTR: row.ctr, + Position: row.position, +})); diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/deviceBreakdown.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/deviceBreakdown.js index 0c3f4ee2..53960961 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/deviceBreakdown.js +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/deviceBreakdown.js @@ -1,9 +1,9 @@ const rows = data.rows ?? []; -result = rows.map(row => ({ +result = rows.map((row) => ({ Device: row.keys?.[0], Clicks: row.clicks, Impressions: row.impressions, - CTR: Number((row.ctr * 100).toFixed(2)), - Position: Number(row.position.toFixed(2)) -})); \ No newline at end of file + CTR: row.ctr, + Position: row.position, +})); diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pagePerformanceOverTime.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pagePerformanceOverTime.js index aee4786c..86c1abfd 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pagePerformanceOverTime.js +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pagePerformanceOverTime.js @@ -4,6 +4,6 @@ result = rows.map(row => ({ Date: new Date(row.keys?.[0]), Clicks: row.clicks, Impressions: row.impressions, - CTR: Number((row.ctr * 100).toFixed(2)), - Position: Number(row.position.toFixed(1)) + CTR: row.ctr, + Position: row.position })); \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pagePerformanceSummary.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pagePerformanceSummary.js new file mode 100644 index 00000000..ecc6620c --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pagePerformanceSummary.js @@ -0,0 +1,9 @@ +const rows = data.rows ?? []; + +result = rows.map((row) => ({ + Page: row.keys?.[0], + Clicks: row.clicks, + Impressions: row.impressions, + CTR: row.ctr, + Position: row.position, +})); diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pages.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pages.js index 9cabe3ee..ecc6620c 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pages.js +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pages.js @@ -1,9 +1,9 @@ const rows = data.rows ?? []; -result = rows.map(row => ({ - Page: row.keys?.[0], - Clicks: row.clicks, - Impressions: row.impressions, - CTR: Number((row.ctr * 100).toFixed(2)), - Position: Number(row.position.toFixed(2)) -})); \ No newline at end of file +result = rows.map((row) => ({ + Page: row.keys?.[0], + Clicks: row.clicks, + Impressions: row.impressions, + CTR: row.ctr, + Position: row.position, +})); diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodPerformanceOverTime.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodPerformanceOverTime.js index 76f3cd26..250c60fe 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodPerformanceOverTime.js +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodPerformanceOverTime.js @@ -1,9 +1,9 @@ const rows = data.rows ?? []; -result = rows.map(row => ({ +result = rows.map((row) => ({ Date: row.keys?.[0], Clicks: row.clicks, Impressions: row.impressions, - CTR: Number((row.ctr * 100).toFixed(2)), - Position: Number(row.position.toFixed(1)) -})); \ No newline at end of file + CTR: row.ctr, + Position: row.position, +})); diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodQueriesByPage.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodQueriesByPage.js index 9cad4f37..00ecc620 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodQueriesByPage.js +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/previousPeriodQueriesByPage.js @@ -1,9 +1,9 @@ const rows = data.rows ?? []; -result = rows.map(row => ({ - Query: row.keys?.[0], - Clicks: row.clicks, - Impressions: row.impressions, - CTR: Number((row.ctr * 100).toFixed(2)), - Position: Number(row.position.toFixed(1)) -})); \ No newline at end of file +result = rows.map((row) => ({ + Query: row.keys?.[0], + Clicks: row.clicks, + Impressions: row.impressions, + CTR: row.ctr, + Position: row.position, +})); diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/queries.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/queries.js new file mode 100644 index 00000000..7450d575 --- /dev/null +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/queries.js @@ -0,0 +1,11 @@ +const rows = data.rows ?? []; + +result = rows.map((row) => { + return { + Query: row.keys?.[0], + Clicks: row.clicks, + Impressions: row.impressions, + CTR: row.ctr, + Position: row.position, + }; +}); diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script1.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script1.js deleted file mode 100644 index bac7be20..00000000 --- a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script1.js +++ /dev/null @@ -1,9 +0,0 @@ -const rows = data.rows ?? []; - -result = rows.map(row => ({ - Page: row.keys?.[0], - Clicks: row.clicks, - Impressions: row.impressions, - CTR: Number((row.ctr * 100).toFixed(2)), - Position: Number(row.position.toFixed(1)) -})); \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script2.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script2.js deleted file mode 100644 index 63a2d10b..00000000 --- a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/script2.js +++ /dev/null @@ -1,11 +0,0 @@ -const rows = data.rows ?? []; - -result = rows.map(row => { - return { - Query: row.keys?.[0], - Clicks: row.clicks, - Impressions: row.impressions, - CTR: Number((row.ctr * 100).toFixed(2)), - Position: Number(row.position.toFixed(2)) - }; -}); \ No newline at end of file diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceOverTime.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceOverTime.js index 8fe3ebb4..e9b7fd3c 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceOverTime.js +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceOverTime.js @@ -1,11 +1,11 @@ const rows = data.rows ?? []; -result = rows.map(row => { +result = rows.map((row) => { return { Date: new Date(row.keys?.[0]), Clicks: row.clicks, Impressions: row.impressions, - CTR: Number((row.ctr * 100).toFixed(2)), - Position: Number(row.position.toFixed(2)) + CTR: row.ctr, + Position: row.position, }; -}); \ No newline at end of file +}); diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceSummary.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceSummary.js index 6f970d6c..36fb66fd 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceSummary.js +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/sitePerformanceSummary.js @@ -1,8 +1,10 @@ const row = data.rows?.[0] ?? {}; -result = [{ - Impressions: row.impressions ?? 0, - Clicks: row.clicks ?? 0, - CTR: Number(((row.ctr ?? 0) * 100).toFixed(2)), - Position: Number((row.position ?? 0).toFixed(2)) -}]; \ No newline at end of file +result = [ + { + Impressions: row.impressions ?? 0, + Clicks: row.clicks ?? 0, + CTR: row.ctr ?? 0, + Position: row.position ?? 0, + }, +]; diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceOverTime.json b/plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceOverTime.json index 1e3761e9..5d79c2ff 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceOverTime.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceOverTime.json @@ -15,10 +15,8 @@ "postBody": { "startDate": "{{new Date(timeframe.start).toISOString().split('T')[0]}}", "endDate": "{{new Date(timeframe.end).toISOString().split('T')[0]}}", - "dimensions": [ - "date" - ], - "rowLimit": 25000, + "dimensions": ["date"], + "rowLimit": 2500, "dataState": "final" }, "postRequestScript": "postRequest/sitePerformanceOverTime.js", @@ -36,11 +34,25 @@ ], "name": "Date" }, + { + "pattern": ".*" + }, + { + "shape": [ + "percent", + { + "thousandsSeparator": true, + "decimalPlaces": 2, + "asZeroToOne": true + } + ], + "name": "CTR" + }, { "pattern": ".*" } ], "providesPluginDiagnostics": true, "timeframes": true, - "tags": [] -} \ No newline at end of file + "tags": ["SEO", "Analytics"] +} diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceSummary.json b/plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceSummary.json index 159cfce9..d74b25ce 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceSummary.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/sitePerformanceSummary.json @@ -20,7 +20,23 @@ "getArgs": [], "headers": [] }, + "metadata": [ + { + "shape": [ + "percent", + { + "thousandsSeparator": true, + "decimalPlaces": 2, + "asZeroToOne": true + } + ], + "name": "CTR" + }, + { + "pattern": ".*" + } + ], "providesPluginDiagnostics": true, "timeframes": true, - "tags": [] -} \ No newline at end of file + "tags": ["SEO", "Analytics"] +} diff --git a/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json b/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json index e8d4e513..97e3a3d2 100644 --- a/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json +++ b/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json @@ -148,7 +148,7 @@ "activePluginConfigIds": [ "{{configId}}" ], - "title": "Organic search performance", + "title": "Period performance change", "baseTile": "data-stream-base-tile", "visualisation": { "type": "data-stream-table", diff --git a/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json b/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json index 5b9bc874..eb076382 100644 --- a/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json +++ b/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json @@ -173,7 +173,7 @@ "{{configId}}" ], "baseTile": "data-stream-base-tile", - "title": "Organic Search Performance", + "title": "Period performance change", "visualisation": { "type": "data-stream-table", "config": { diff --git a/plugins/GoogleSearchConsole/v1/metadata.json b/plugins/GoogleSearchConsole/v1/metadata.json index f4cdb473..17a1a579 100644 --- a/plugins/GoogleSearchConsole/v1/metadata.json +++ b/plugins/GoogleSearchConsole/v1/metadata.json @@ -3,7 +3,7 @@ "displayName": "Google Search Console", "version": "1.0.0", "author": { - "name": "Daniel.Hodgson@squaredup.com", + "name": "@Daniel-Hodgson-SquaredUp", "type": "community" }, "description": "Monitor performance metrics for a GSC property", From ffdf9a4a734130daab3d93c4df1e1e2ce518a160 Mon Sep 17 00:00:00 2001 From: Dan H Date: Wed, 24 Jun 2026 10:31:35 +0100 Subject: [PATCH 5/9] Applied suggested changes form coderabbitai: Use help instead of description for UI fields The metadata no longer uses the product abbreviation This metadata now includes the links array Removed plugin abbreviation from source type Fixed markdown violations Made period-change SQL null-safe for empty periods Tiles now title-case Default position of 0 no longer mis-bucketed Use the full page URL in the filter for queriesByPage Fixed description for previousPeriodPerformanceOverTime Fixed casing for pageUrLs (now pageUrls) Ignored suggestions that seemed incorrect or nitpicky --- .../v1/dataStreams/pageDistribution.json | 2 +- .../dataStreams/pagePerformanceOverTime.json | 2 +- .../dataStreams/pagePerformanceSummary.json | 2 +- .../previousPeriodPagePerformance.json | 2 +- .../previousPeriodPerformanceOverTime.json | 2 +- .../previousPeriodQueriesByPage.json | 2 +- .../v1/dataStreams/queriesByPage.json | 4 +- .../scripts/postRequest/pageDistribution.js | 26 ++++++----- .../v1/defaultContent/pageOverview.dash.json | 14 +++--- .../v1/defaultContent/scopes.json | 2 +- .../v1/defaultContent/siteOverview.dash.json | 16 +++---- plugins/GoogleSearchConsole/v1/docs/README.md | 46 +++++++++++-------- .../v1/indexDefinitions/default.json | 2 +- plugins/GoogleSearchConsole/v1/metadata.json | 18 ++++++-- plugins/GoogleSearchConsole/v1/ui.json | 6 +-- 15 files changed, 84 insertions(+), 62 deletions(-) diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/pageDistribution.json b/plugins/GoogleSearchConsole/v1/dataStreams/pageDistribution.json index 6b6cd57b..a516b91f 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/pageDistribution.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/pageDistribution.json @@ -47,7 +47,7 @@ "matches": { "sourceType": { "type": "equals", - "value": "gsc-page" + "value": "page" } }, "validation": { diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceOverTime.json b/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceOverTime.json index ef3f040b..00eb08c7 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceOverTime.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceOverTime.json @@ -61,7 +61,7 @@ "matches": { "sourceType": { "type": "equals", - "value": "gsc-page" + "value": "page" } }, "validation": { diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceSummary.json b/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceSummary.json index 26347973..d254960a 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceSummary.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/pagePerformanceSummary.json @@ -61,7 +61,7 @@ "matches": { "sourceType": { "type": "equals", - "value": "gsc-page" + "value": "page" } }, "validation": { diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPagePerformance.json b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPagePerformance.json index e734f799..b2a8bd68 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPagePerformance.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPagePerformance.json @@ -64,7 +64,7 @@ "matches": { "sourceType": { "type": "equals", - "value": "gsc-page" + "value": "page" } }, "validation": { diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPerformanceOverTime.json b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPerformanceOverTime.json index 0125e6dd..1c4228b9 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPerformanceOverTime.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodPerformanceOverTime.json @@ -1,7 +1,7 @@ { "name": "previousPeriodPerformanceOverTime", "displayName": "Previous period performance over time", - "description": "Returns daily performance for the previous period of a given timeframe for the selected page", + "description": "Returns daily performance for the previous period of a given timeframe", "baseDataSourceName": "httpRequestUnscoped", "visibility": { "type": "hidden" diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodQueriesByPage.json b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodQueriesByPage.json index 0115841d..be7214a5 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodQueriesByPage.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/previousPeriodQueriesByPage.json @@ -64,7 +64,7 @@ "matches": { "sourceType": { "type": "equals", - "value": "gsc-page" + "value": "page" } }, "validation": { diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/queriesByPage.json b/plugins/GoogleSearchConsole/v1/dataStreams/queriesByPage.json index 66c8b3a1..0fa658a6 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/queriesByPage.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/queriesByPage.json @@ -22,7 +22,7 @@ { "dimension": "page", "operator": "equals", - "expression": "{{scope?.[0]?.rawId?.[0]}}" + "expression": "{{scope?.[0]?.name}}" } ] } @@ -62,7 +62,7 @@ "matches": { "sourceType": { "type": "equals", - "value": "gsc-page" + "value": "page" } }, "validation": { diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageDistribution.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageDistribution.js index aead2978..eb825b64 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageDistribution.js +++ b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageDistribution.js @@ -1,17 +1,19 @@ const rows = data.rows ?? []; -result = rows.map(row => { - const position = row.position ?? 0; +result = rows + .filter((row) => row.position != null) + .map((row) => { + const position = row.position; - let Bucket = "51+"; + let Bucket = "51+"; - if (position <= 3) Bucket = "1-3"; - else if (position <= 10) Bucket = "4-10"; - else if (position <= 20) Bucket = "11-20"; - else if (position <= 50) Bucket = "21-50"; + if (position <= 3) Bucket = "1-3"; + else if (position <= 10) Bucket = "4-10"; + else if (position <= 20) Bucket = "11-20"; + else if (position <= 50) Bucket = "21-50"; - return { - Bucket, - Queries: 1 - }; -}); \ No newline at end of file + return { + Bucket, + Queries: 1, + }; + }); diff --git a/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json b/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json index 97e3a3d2..4e8777aa 100644 --- a/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json +++ b/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json @@ -35,7 +35,7 @@ "{{configId}}" ], "baseTile": "data-stream-base-tile", - "title": "Page summary", + "title": "Page Summary", "visualisation": { "type": "data-stream-table", "config": { @@ -148,7 +148,7 @@ "activePluginConfigIds": [ "{{configId}}" ], - "title": "Period performance change", + "title": "Period Performance Change", "baseTile": "data-stream-base-tile", "visualisation": { "type": "data-stream-table", @@ -356,7 +356,7 @@ "activePluginConfigIds": [ "{{configId}}" ], - "title": "Ranking distribution", + "title": "Ranking Distribution", "visualisation": { "type": "data-stream-bar-chart", "config": { @@ -453,7 +453,7 @@ "{{configId}}" ], "baseTile": "data-stream-base-tile", - "title": "Query opportunities", + "title": "Query Opportunities", "visualisation": { "type": "data-stream-table", "config": { @@ -516,7 +516,7 @@ "{{configId}}" ], "baseTile": "data-stream-base-tile", - "title": "Top queries", + "title": "Top Queries", "visualisation": { "type": "data-stream-table", "config": { @@ -569,7 +569,7 @@ "activePluginConfigIds": [ "{{configId}}" ], - "title": "Page performance over time", + "title": "Page Performance Over Time", "visualisation": { "type": "data-stream-line-graph", "config": { @@ -617,7 +617,7 @@ "activePluginConfigIds": [ "{{configId}}" ], - "title": "Ranking over time", + "title": "Ranking Over Time", "visualisation": { "type": "data-stream-line-graph", "config": { diff --git a/plugins/GoogleSearchConsole/v1/defaultContent/scopes.json b/plugins/GoogleSearchConsole/v1/defaultContent/scopes.json index b8bfcf23..bdd2d4bc 100644 --- a/plugins/GoogleSearchConsole/v1/defaultContent/scopes.json +++ b/plugins/GoogleSearchConsole/v1/defaultContent/scopes.json @@ -5,7 +5,7 @@ "sourceType": { "type": "oneOf", "values": [ - "gsc-page" + "page" ] } }, diff --git a/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json b/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json index eb076382..7d3750a0 100644 --- a/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json +++ b/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json @@ -39,7 +39,7 @@ "{{configId}}" ], "baseTile": "data-stream-base-tile", - "title": "Top queries", + "title": "Top Queries", "visualisation": { "type": "data-stream-table", "config": { @@ -85,7 +85,7 @@ "{{configId}}" ], "baseTile": "data-stream-base-tile", - "title": "Site summary", + "title": "Site Summary", "visualisation": { "type": "data-stream-table", "config": { @@ -150,7 +150,7 @@ "tableName": "dataset2" } ], - "sql": "WITH current_period AS (\r\n SELECT\r\n SUM(Clicks) AS Clicks,\r\n SUM(Impressions) AS Impressions,\r\n SUM(Clicks) / NULLIF(SUM(Impressions), 0) * 100 AS CTR,\r\n AVG(Position) AS Position\r\n FROM dataset2\r\n),\r\n\r\nprevious_period AS (\r\n SELECT\r\n SUM(Clicks) AS Clicks,\r\n SUM(Impressions) AS Impressions,\r\n SUM(Clicks) / NULLIF(SUM(Impressions), 0) * 100 AS CTR,\r\n AVG(Position) AS Position\r\n FROM dataset1\r\n)\r\n\r\nSELECT\r\n ROUND(((current_period.Clicks - previous_period.Clicks) / NULLIF(previous_period.Clicks, 0)) * 100, 2) AS \"Clicks Change %\",\r\n\r\n ROUND(((current_period.Impressions - previous_period.Impressions) / NULLIF(previous_period.Impressions, 0)) * 100, 2) AS \"Impressions Change %\",\r\n\r\n ROUND(((current_period.CTR - previous_period.CTR) / NULLIF(previous_period.CTR, 0)) * 100, 2) AS \"CTR Change %\",\r\n\r\n ROUND(previous_period.Position - current_period.Position, 2) AS \"Position Change\"\r\n\r\nFROM current_period\r\nCROSS JOIN previous_period" + "sql": "WITH current_period AS ( SELECT COALESCE(SUM(Clicks), 0) AS Clicks, COALESCE(SUM(Impressions), 0) AS Impressions, CASE WHEN COALESCE(SUM(Impressions), 0) = 0 THEN 0 ELSE SUM(Clicks) / SUM(Impressions) * 100 END AS CTR, AVG(Position) AS Position FROM dataset2 ), previous_period AS ( SELECT COALESCE(SUM(Clicks), 0) AS Clicks, COALESCE(SUM(Impressions), 0) AS Impressions, CASE WHEN COALESCE(SUM(Impressions), 0) = 0 THEN 0 ELSE SUM(Clicks) / SUM(Impressions) * 100 END AS CTR, AVG(Position) AS Position FROM dataset1 ) SELECT CASE WHEN previous_period.Clicks = 0 THEN 0 ELSE ROUND(((current_period.Clicks - previous_period.Clicks) / previous_period.Clicks) * 100, 2) END AS \"Clicks Change %\", CASE WHEN previous_period.Impressions = 0 THEN 0 ELSE ROUND(((current_period.Impressions - previous_period.Impressions) / previous_period.Impressions) * 100, 2) END AS \"Impressions Change %\", CASE WHEN previous_period.CTR = 0 THEN 0 ELSE ROUND(((current_period.CTR - previous_period.CTR) / previous_period.CTR) * 100, 2) END AS \"CTR Change %\", CASE WHEN previous_period.Position IS NULL OR current_period.Position IS NULL THEN 0 ELSE ROUND(previous_period.Position - current_period.Position, 2) END AS \"Position Change\" FROM current_period CROSS JOIN previous_period" }, "id": "datastream-sql" }, @@ -173,7 +173,7 @@ "{{configId}}" ], "baseTile": "data-stream-base-tile", - "title": "Period performance change", + "title": "Period Performance Change", "visualisation": { "type": "data-stream-table", "config": { @@ -218,7 +218,7 @@ "activePluginConfigIds": [ "{{configId}}" ], - "title": "Site performance over time", + "title": "Site Performance Over Time", "visualisation": { "type": "data-stream-line-graph", "config": { @@ -259,7 +259,7 @@ "{{configId}}" ], "baseTile": "data-stream-base-tile", - "title": "Top pages", + "title": "Top Pages", "visualisation": { "type": "data-stream-table", "config": { @@ -316,7 +316,7 @@ "activePluginConfigIds": [ "{{configId}}" ], - "title": "Country breakdown", + "title": "Country Breakdown", "visualisation": { "type": "data-stream-table", "config": { @@ -354,7 +354,7 @@ "activePluginConfigIds": [ "{{configId}}" ], - "title": "Device breakdown", + "title": "Device Breakdown", "visualisation": { "type": "data-stream-bar-chart", "config": { diff --git a/plugins/GoogleSearchConsole/v1/docs/README.md b/plugins/GoogleSearchConsole/v1/docs/README.md index 61407cc0..d8ff804c 100644 --- a/plugins/GoogleSearchConsole/v1/docs/README.md +++ b/plugins/GoogleSearchConsole/v1/docs/README.md @@ -25,30 +25,37 @@ 2. Click **+ Create credentials** and select **OAuth client ID** 3. If prompted, configure the OAuth consent screen: - - Choose **External** - - Enter the required application details - - Add the following scope: - ``` - https://www.googleapis.com/auth/webmasters.readonly - ``` + + - Choose **External** + - Enter the required application details + - Add the following scope: + + ```text + https://www.googleapis.com/auth/webmasters.readonly + ``` 4. On the **Create OAuth client ID** page: - - Select **Web application** as the application type - - Enter a name for your OAuth client + + - Select **Web application** as the application type + - Enter a name for your OAuth client 5. Add authorized JavaScript origins: - - Click **+ Add URI** under **Authorized JavaScript origins** - - Enter: - ``` - https://app.squaredup.com - ``` + + - Click **+ Add URI** under **Authorized JavaScript origins** + - Enter: + + ```text + https://app.squaredup.com + ``` 6. Add authorized redirect URIs: - - Click **+ Add URI** under **Authorized redirect URIs** - - Enter: - ``` - https://app.squaredup.com/settings/pluginsoauth2 - ``` + + - Click **+ Add URI** under **Authorized redirect URIs** + - Enter: + + ```text + https://app.squaredup.com/settings/pluginsoauth2 + ``` 7. Click **Create** @@ -82,7 +89,8 @@ Verify that: - The Google Search Console API is enabled - The Client ID and Client Secret are correct - The redirect URI exactly matches: - ``` + + ```text https://app.squaredup.com/settings/pluginsoauth2 ``` diff --git a/plugins/GoogleSearchConsole/v1/indexDefinitions/default.json b/plugins/GoogleSearchConsole/v1/indexDefinitions/default.json index af67b519..bb12f84a 100644 --- a/plugins/GoogleSearchConsole/v1/indexDefinitions/default.json +++ b/plugins/GoogleSearchConsole/v1/indexDefinitions/default.json @@ -11,7 +11,7 @@ "id": "value", "name": "label", "type": { - "value": "gsc-page" + "value": "page" } } } diff --git a/plugins/GoogleSearchConsole/v1/metadata.json b/plugins/GoogleSearchConsole/v1/metadata.json index 17a1a579..0df51821 100644 --- a/plugins/GoogleSearchConsole/v1/metadata.json +++ b/plugins/GoogleSearchConsole/v1/metadata.json @@ -6,7 +6,7 @@ "name": "@Daniel-Hodgson-SquaredUp", "type": "community" }, - "description": "Monitor performance metrics for a GSC property", + "description": "Monitor search performance metrics for a Google Search Console property.", "category": "Analytics", "type": "hybrid", "schemaVersion": "2.0", @@ -38,5 +38,17 @@ ], "oauth2Scope": "https://www.googleapis.com/auth/webmasters.readonly" } - } -} \ No newline at end of file + }, + "links": [ + { + "category": "documentation", + "url": "https://github.com/squaredup/plugins/blob/main/plugins/GoogleSearchConsole/v1/docs/README.md", + "label": "Help adding this plugin" + }, + { + "category": "source", + "url": "https://github.com/squaredup/plugins/tree/main/plugins/GoogleSearchConsole/v1", + "label": "Repository" + } + ] +} diff --git a/plugins/GoogleSearchConsole/v1/ui.json b/plugins/GoogleSearchConsole/v1/ui.json index 5db699c3..e178056d 100644 --- a/plugins/GoogleSearchConsole/v1/ui.json +++ b/plugins/GoogleSearchConsole/v1/ui.json @@ -3,7 +3,7 @@ "name": "siteUrl", "type": "text", "label": "Search Console property URL", - "description": "Enter the exact URL-prefix property from Google Search Console. Example: https://example.com/", + "help": "Enter the exact URL-prefix property from Google Search Console. Example: https://example.com/", "placeholder": "https://example.com/", "validation": { "required": true @@ -13,7 +13,7 @@ "name": "oauth2ClientId", "type": "text", "label": "Google OAuth client ID", - "description": "Enter the OAuth client ID from your Google Cloud project.", + "help": "Enter the OAuth client ID from your Google Cloud project.", "placeholder": "1234567890-example.apps.googleusercontent.com", "validation": { "required": true @@ -23,7 +23,7 @@ "name": "oauth2ClientSecret", "type": "password", "label": "Google OAuth client secret", - "description": "Enter the OAuth client secret from your Google Cloud project.", + "help": "Enter the OAuth client secret from your Google Cloud project.", "validation": { "required": true } From a73c2e438ea05270569b6d21af2d280f8ef4426f Mon Sep 17 00:00:00 2001 From: Dan H Date: Wed, 24 Jun 2026 10:52:08 +0100 Subject: [PATCH 6/9] Updated pageUrLs -> pageUrls casing fix missed from last commit --- plugins/GoogleSearchConsole/v1/dataStreams/pageUrLs.json | 4 ++-- plugins/GoogleSearchConsole/v1/indexDefinitions/default.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/pageUrLs.json b/plugins/GoogleSearchConsole/v1/dataStreams/pageUrLs.json index ee8fd342..916be4f4 100644 --- a/plugins/GoogleSearchConsole/v1/dataStreams/pageUrLs.json +++ b/plugins/GoogleSearchConsole/v1/dataStreams/pageUrLs.json @@ -1,5 +1,5 @@ { - "name": "pageUrLs", + "name": "pageUrls", "displayName": "Page URLs", "description": "Returns a list of URLs with impressions in the last year", "baseDataSourceName": "httpRequestUnscoped", @@ -20,7 +20,7 @@ ], "rowLimit": 5000 }, - "postRequestScript": "postRequest/pageUrLs.js", + "postRequestScript": "postRequest/pageUrls.js", "getArgs": [], "headers": [] }, diff --git a/plugins/GoogleSearchConsole/v1/indexDefinitions/default.json b/plugins/GoogleSearchConsole/v1/indexDefinitions/default.json index bb12f84a..356d55f2 100644 --- a/plugins/GoogleSearchConsole/v1/indexDefinitions/default.json +++ b/plugins/GoogleSearchConsole/v1/indexDefinitions/default.json @@ -3,7 +3,7 @@ { "name": "Import pages", "dataStream": { - "name": "pageUrLs", + "name": "pageUrls", "config": {} }, "timeframe": "none", From 93bcd6f3998d874a3761c66a21451146be26870a Mon Sep 17 00:00:00 2001 From: Dan H Date: Wed, 24 Jun 2026 15:08:54 +0100 Subject: [PATCH 7/9] Removed hard-coded scope bindings from OOB dashboards --- .../v1/defaultContent/pageOverview.dash.json | 52 ------------------- .../v1/defaultContent/siteOverview.dash.json | 13 ----- 2 files changed, 65 deletions(-) diff --git a/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json b/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json index 4e8777aa..94bc97c6 100644 --- a/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json +++ b/plugins/GoogleSearchConsole/v1/defaultContent/pageOverview.dash.json @@ -130,19 +130,6 @@ }, "id": "datastream-sql" }, - "scope": { - "query": "g.V().has('id', within(ids_MI6UfjAoqy17Fe9Ug6ST))", - "bindings": { - "ids_MI6UfjAoqy17Fe9Ug6ST": [ - "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" - ] - }, - "queryDetail": { - "ids": [ - "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" - ] - } - }, "_type": "tile/data-stream", "description": "", "activePluginConfigIds": [ @@ -242,19 +229,6 @@ }, "id": "datastream-sql" }, - "scope": { - "query": "g.V().has('id', within(ids_d0XpnAS5M7Up3bmNCZUB))", - "bindings": { - "ids_d0XpnAS5M7Up3bmNCZUB": [ - "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" - ] - }, - "queryDetail": { - "ids": [ - "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" - ] - } - }, "_type": "tile/data-stream", "description": "", "activePluginConfigIds": [ @@ -338,19 +312,6 @@ }, "id": "datastream-sql" }, - "scope": { - "query": "g.V().has('id', within(ids_x17OQVG9BsPtxhZAiSKq))", - "bindings": { - "ids_x17OQVG9BsPtxhZAiSKq": [ - "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" - ] - }, - "queryDetail": { - "ids": [ - "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" - ] - } - }, "_type": "tile/data-stream", "description": "", "activePluginConfigIds": [ @@ -434,19 +395,6 @@ }, "id": "datastream-sql" }, - "scope": { - "query": "g.V().has('id', within(ids_ld2AmVYZkZ4TEH5rBCXD))", - "bindings": { - "ids_ld2AmVYZkZ4TEH5rBCXD": [ - "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" - ] - }, - "queryDetail": { - "ids": [ - "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" - ] - } - }, "_type": "tile/data-stream", "description": "", "activePluginConfigIds": [ diff --git a/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json b/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json index 7d3750a0..5b8e56fc 100644 --- a/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json +++ b/plugins/GoogleSearchConsole/v1/defaultContent/siteOverview.dash.json @@ -154,19 +154,6 @@ }, "id": "datastream-sql" }, - "scope": { - "query": "g.V().has('id', within(ids_CJ7tYgjdolxSg53jHrjr))", - "bindings": { - "ids_CJ7tYgjdolxSg53jHrjr": [ - "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" - ] - }, - "queryDetail": { - "ids": [ - "node-1dwkxV4HX7tME4WtZkj2r04TirpbysXMf3ej9-a1txyPzIR6b4Z1ctJ0Ks" - ] - } - }, "_type": "tile/data-stream", "description": "", "activePluginConfigIds": [ From aff69ca08fb30290ae7042896047e7db92d27fb0 Mon Sep 17 00:00:00 2001 From: Dan H Date: Wed, 24 Jun 2026 15:46:15 +0100 Subject: [PATCH 8/9] Fixed filename mismatch as git hadn't noticed the change --- .../v1/dataStreams/{pageUrLs.json => pageUrls.json} | 0 .../dataStreams/scripts/postRequest/{pageUrLs.js => pageUrls.js} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename plugins/GoogleSearchConsole/v1/dataStreams/{pageUrLs.json => pageUrls.json} (100%) rename plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/{pageUrLs.js => pageUrls.js} (100%) diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/pageUrLs.json b/plugins/GoogleSearchConsole/v1/dataStreams/pageUrls.json similarity index 100% rename from plugins/GoogleSearchConsole/v1/dataStreams/pageUrLs.json rename to plugins/GoogleSearchConsole/v1/dataStreams/pageUrls.json diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageUrLs.js b/plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageUrls.js similarity index 100% rename from plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageUrLs.js rename to plugins/GoogleSearchConsole/v1/dataStreams/scripts/postRequest/pageUrls.js From ae90aac86862aa2ddf885b4b09ababd97ffe93d4 Mon Sep 17 00:00:00 2001 From: Dan H Date: Thu, 25 Jun 2026 15:58:25 +0100 Subject: [PATCH 9/9] Updated icon to use current logo --- plugins/GoogleSearchConsole/v1/icon.svg | 34 ++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/plugins/GoogleSearchConsole/v1/icon.svg b/plugins/GoogleSearchConsole/v1/icon.svg index fc5a0504..b210a9f7 100644 --- a/plugins/GoogleSearchConsole/v1/icon.svg +++ b/plugins/GoogleSearchConsole/v1/icon.svg @@ -1 +1,33 @@ - \ No newline at end of file + + + + + + + + + + + + + \ No newline at end of file