diff --git a/plugins/GoogleSearchConsole/v1/dataStreams/countryBreakdown.json b/plugins/GoogleSearchConsole/v1/dataStreams/countryBreakdown.json new file mode 100644 index 0000000..ccb05ad --- /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 0000000..93b605a --- /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 0000000..2d118ed --- /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 0000000..6d93f5d --- /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 0000000..675ddf7 --- /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 0000000..e4a5de8 --- /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 0000000..0993d17 --- /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 0000000..9ffed41 --- /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 0000000..63f862a --- /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 0000000..b029a1f --- /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 0000000..8eb1b87 --- /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 0000000..a296ede --- /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 0000000..e573e04 --- /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 0000000..0c3f4ee --- /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 0000000..aead297 --- /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 0000000..aee4786 --- /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 0000000..4ea7a9c --- /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 0000000..9cabe3e --- /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 0000000..76f3cd2 --- /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 0000000..9cad4f3 --- /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 0000000..bac7be2 --- /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 0000000..63a2d10 --- /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 0000000..8fe3ebb --- /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 0000000..6f970d6 --- /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 0000000..1e3761e --- /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 0000000..159cfce --- /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 0000000..51b75d8 --- /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 0000000..577bf7e --- /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 0000000..b8bfcf2 --- /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 0000000..ac15049 --- /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 0000000..61407cc --- /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 0000000..fc5a050 --- /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 0000000..af67b51 --- /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 0000000..f4cdb47 --- /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 0000000..5db699c --- /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