gscdump 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -9
- package/dist/analysis/index.d.mts +487 -0
- package/dist/analysis/index.mjs +810 -0
- package/dist/index.d.mts +81 -912
- package/dist/index.mjs +195 -3455
- package/dist/query/index.d.mts +35 -52
- package/dist/query/index.mjs +95 -90
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -66,7 +66,7 @@ Drizzle-style query builder with full type safety. Filter constraints flow throu
|
|
|
66
66
|
```ts
|
|
67
67
|
import { and, between, contains, country, Country, date, device, Device, eq, gsc, inArray, page } from 'gscdump/query'
|
|
68
68
|
|
|
69
|
-
const
|
|
69
|
+
const body = gsc
|
|
70
70
|
.select('page', 'query', 'device', 'country')
|
|
71
71
|
.where(and(
|
|
72
72
|
eq(device, Device.MOBILE),
|
|
@@ -74,14 +74,9 @@ const result = await gsc
|
|
|
74
74
|
contains(page, '/blog/'),
|
|
75
75
|
between(date, '2024-01-01', '2024-01-31')
|
|
76
76
|
))
|
|
77
|
-
.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
// Fully typed results - narrowed by filters
|
|
81
|
-
result.rows[0].device // type: 'MOBILE' (narrowed by eq)
|
|
82
|
-
result.rows[0].country // type: 'usa' | 'gbr' (narrowed by inArray)
|
|
83
|
-
result.rows[0].page // type: string (contains doesn't narrow)
|
|
84
|
-
result.rows[0].clicks // type: number
|
|
77
|
+
.toBody()
|
|
78
|
+
|
|
79
|
+
// Use with client.searchAnalytics.query(siteUrl, body)
|
|
85
80
|
```
|
|
86
81
|
|
|
87
82
|
**With date helpers:**
|
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
import "ofetch";
|
|
2
|
+
import { indexing_v3 } from "@googleapis/indexing/v3";
|
|
3
|
+
import { searchconsole_v1 } from "@googleapis/searchconsole/v1";
|
|
4
|
+
|
|
5
|
+
//#region src/analysis/types.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Shared types for analysis functions.
|
|
8
|
+
*/
|
|
9
|
+
type SortOrder = 'asc' | 'desc';
|
|
10
|
+
/** Base search metrics */
|
|
11
|
+
interface BaseMetrics {
|
|
12
|
+
clicks: number;
|
|
13
|
+
impressions: number;
|
|
14
|
+
ctr: number;
|
|
15
|
+
position: number;
|
|
16
|
+
}
|
|
17
|
+
/** Keyword row from query */
|
|
18
|
+
interface KeywordRow extends BaseMetrics {
|
|
19
|
+
query: string;
|
|
20
|
+
page?: string;
|
|
21
|
+
}
|
|
22
|
+
/** Page row from query */
|
|
23
|
+
interface PageRow extends BaseMetrics {
|
|
24
|
+
page: string;
|
|
25
|
+
}
|
|
26
|
+
/** Date row from query */
|
|
27
|
+
interface DateRow extends BaseMetrics {
|
|
28
|
+
date: string;
|
|
29
|
+
}
|
|
30
|
+
/** Coerce nullable number to number, defaulting to 0 */
|
|
31
|
+
declare function num(value: number | null | undefined): number;
|
|
32
|
+
/** Create a generic sorter for any metric type */
|
|
33
|
+
declare function createSorter<T, M extends string>(getValue: (item: T, metric: M) => number, defaultMetric: M, defaultOrder?: SortOrder): (items: T[], sortBy?: M, sortOrder?: SortOrder) => T[];
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/analysis/brand.d.ts
|
|
36
|
+
interface BrandSegmentationOptions {
|
|
37
|
+
/** Brand terms to match against keywords (case-insensitive) */
|
|
38
|
+
brandTerms: string[];
|
|
39
|
+
/** Minimum impressions for a keyword to be included. Default: 10 */
|
|
40
|
+
minImpressions?: number;
|
|
41
|
+
}
|
|
42
|
+
interface BrandSummary {
|
|
43
|
+
brandClicks: number;
|
|
44
|
+
nonBrandClicks: number;
|
|
45
|
+
brandShare: number;
|
|
46
|
+
brandImpressions: number;
|
|
47
|
+
nonBrandImpressions: number;
|
|
48
|
+
}
|
|
49
|
+
interface BrandSegmentationResult {
|
|
50
|
+
brand: KeywordRow[];
|
|
51
|
+
nonBrand: KeywordRow[];
|
|
52
|
+
summary: BrandSummary;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Segments keywords into brand and non-brand based on provided brand terms.
|
|
56
|
+
*/
|
|
57
|
+
declare function analyzeBrandSegmentation(keywords: KeywordRow[], options: BrandSegmentationOptions): BrandSegmentationResult;
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/analysis/clustering.d.ts
|
|
60
|
+
type ClusterType = 'prefix' | 'intent' | 'both';
|
|
61
|
+
interface ClusteringOptions {
|
|
62
|
+
/** Minimum keywords for a cluster to be reported. Default: 2 */
|
|
63
|
+
minClusterSize?: number;
|
|
64
|
+
/** Minimum impressions for a keyword to be included. Default: 10 */
|
|
65
|
+
minImpressions?: number;
|
|
66
|
+
/** Clustering method. Default: 'both' */
|
|
67
|
+
clusterBy?: ClusterType;
|
|
68
|
+
}
|
|
69
|
+
interface KeywordCluster {
|
|
70
|
+
clusterName: string;
|
|
71
|
+
clusterType: 'prefix' | 'intent';
|
|
72
|
+
keywords: KeywordRow[];
|
|
73
|
+
totalClicks: number;
|
|
74
|
+
totalImpressions: number;
|
|
75
|
+
avgPosition: number;
|
|
76
|
+
keywordCount: number;
|
|
77
|
+
}
|
|
78
|
+
interface ClusteringResult {
|
|
79
|
+
clusters: KeywordCluster[];
|
|
80
|
+
unclustered: KeywordRow[];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Clusters keywords by intent prefix or common word prefix.
|
|
84
|
+
*/
|
|
85
|
+
declare function analyzeClustering(keywords: KeywordRow[], options?: ClusteringOptions): ClusteringResult;
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region src/analysis/concentration.d.ts
|
|
88
|
+
type ConcentrationRiskLevel = 'low' | 'medium' | 'high';
|
|
89
|
+
interface ConcentrationOptions {
|
|
90
|
+
/** Number of top items to report. Default: 10 */
|
|
91
|
+
topN?: number;
|
|
92
|
+
}
|
|
93
|
+
interface ConcentrationItem {
|
|
94
|
+
key: string;
|
|
95
|
+
clicks: number;
|
|
96
|
+
share: number;
|
|
97
|
+
}
|
|
98
|
+
interface ConcentrationResult {
|
|
99
|
+
/** Gini coefficient: 0 = equal distribution, 1 = fully concentrated */
|
|
100
|
+
giniCoefficient: number;
|
|
101
|
+
/** Herfindahl-Hirschman Index: 0-10000, >2500 = highly concentrated */
|
|
102
|
+
hhi: number;
|
|
103
|
+
/** Percentage of total clicks from top N items */
|
|
104
|
+
topNConcentration: number;
|
|
105
|
+
topNItems: ConcentrationItem[];
|
|
106
|
+
totalItems: number;
|
|
107
|
+
totalClicks: number;
|
|
108
|
+
/** Risk level derived from HHI: <1500 low, 1500-2500 medium, >2500 high */
|
|
109
|
+
riskLevel: ConcentrationRiskLevel;
|
|
110
|
+
}
|
|
111
|
+
interface ConcentrationInput {
|
|
112
|
+
key: string;
|
|
113
|
+
clicks: number;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Analyzes traffic concentration across items (pages or keywords).
|
|
117
|
+
*/
|
|
118
|
+
declare function analyzeConcentration(items: ConcentrationInput[], options?: ConcentrationOptions): ConcentrationResult;
|
|
119
|
+
/**
|
|
120
|
+
* Page concentration analysis.
|
|
121
|
+
*/
|
|
122
|
+
declare function analyzePageConcentration(pages: PageRow[], options?: ConcentrationOptions): ConcentrationResult;
|
|
123
|
+
/**
|
|
124
|
+
* Keyword concentration analysis.
|
|
125
|
+
*/
|
|
126
|
+
declare function analyzeKeywordConcentration(keywords: KeywordRow[], options?: ConcentrationOptions): ConcentrationResult;
|
|
127
|
+
//#endregion
|
|
128
|
+
//#region src/analysis/decay.d.ts
|
|
129
|
+
type DecaySortMetric = 'lostClicks' | 'declinePercent' | 'currentClicks';
|
|
130
|
+
interface DecayOptions {
|
|
131
|
+
/** Minimum clicks in previous period to consider. Default: 50 */
|
|
132
|
+
minPreviousClicks?: number;
|
|
133
|
+
/** Minimum decline percentage (0-1). Default: 0.2 (20%) */
|
|
134
|
+
threshold?: number;
|
|
135
|
+
/** Metric to sort results by. Default: lostClicks */
|
|
136
|
+
sortBy?: DecaySortMetric;
|
|
137
|
+
}
|
|
138
|
+
interface DecayInput {
|
|
139
|
+
current: PageRow[];
|
|
140
|
+
previous: PageRow[];
|
|
141
|
+
}
|
|
142
|
+
interface DecayResult {
|
|
143
|
+
page: string;
|
|
144
|
+
currentClicks: number;
|
|
145
|
+
previousClicks: number;
|
|
146
|
+
lostClicks: number;
|
|
147
|
+
declinePercent: number;
|
|
148
|
+
currentPosition: number;
|
|
149
|
+
previousPosition: number;
|
|
150
|
+
positionDrop: number;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Identifies "decaying" content - pages that have lost significant traffic.
|
|
154
|
+
*/
|
|
155
|
+
declare function analyzeDecay(input: DecayInput, options?: DecayOptions): DecayResult[];
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/core/types.d.ts
|
|
158
|
+
type ApiSite = searchconsole_v1.Schema$WmxSite;
|
|
159
|
+
type ApiSitemap = searchconsole_v1.Schema$WmxSitemap;
|
|
160
|
+
type SearchAnalyticsQuery = searchconsole_v1.Schema$SearchAnalyticsQueryRequest;
|
|
161
|
+
type SearchAnalyticsResponse = searchconsole_v1.Schema$SearchAnalyticsQueryResponse;
|
|
162
|
+
type InspectUrlIndexResponse = searchconsole_v1.Schema$InspectUrlIndexResponse;
|
|
163
|
+
type UrlNotificationMetadata = indexing_v3.Schema$UrlNotificationMetadata;
|
|
164
|
+
type PublishUrlNotificationResponse = indexing_v3.Schema$PublishUrlNotificationResponse;
|
|
165
|
+
//#endregion
|
|
166
|
+
//#region src/query/utils/countries.d.ts
|
|
167
|
+
declare const _default: {
|
|
168
|
+
name: string;
|
|
169
|
+
'alpha-2': string;
|
|
170
|
+
'alpha-3': string;
|
|
171
|
+
'country-code': string;
|
|
172
|
+
}[];
|
|
173
|
+
//#endregion
|
|
174
|
+
//#region src/query/constants.d.ts
|
|
175
|
+
declare const Devices: {
|
|
176
|
+
readonly MOBILE: "MOBILE";
|
|
177
|
+
readonly DESKTOP: "DESKTOP";
|
|
178
|
+
readonly TABLET: "TABLET";
|
|
179
|
+
};
|
|
180
|
+
type Device = typeof Devices[keyof typeof Devices];
|
|
181
|
+
declare const SearchTypes: {
|
|
182
|
+
readonly WEB: "web";
|
|
183
|
+
readonly IMAGE: "image";
|
|
184
|
+
readonly VIDEO: "video";
|
|
185
|
+
readonly NEWS: "news";
|
|
186
|
+
};
|
|
187
|
+
type SearchType = typeof SearchTypes[keyof typeof SearchTypes];
|
|
188
|
+
declare const Countries: { [K in (typeof _default)[number]["alpha-3"]]: Lowercase<K> };
|
|
189
|
+
type Country = typeof Countries[keyof typeof Countries];
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region src/query/types.d.ts
|
|
192
|
+
interface DimensionValueMap {
|
|
193
|
+
query: string;
|
|
194
|
+
page: string;
|
|
195
|
+
country: Country;
|
|
196
|
+
device: Device;
|
|
197
|
+
searchAppearance: string;
|
|
198
|
+
date: string;
|
|
199
|
+
}
|
|
200
|
+
type Dimension = keyof DimensionValueMap;
|
|
201
|
+
interface QueryParamValueMap {
|
|
202
|
+
searchType: SearchType;
|
|
203
|
+
}
|
|
204
|
+
type QueryParamName = keyof QueryParamValueMap;
|
|
205
|
+
type FilterOperator = 'equals' | 'notEquals' | 'contains' | 'notContains' | 'includingRegex' | 'excludingRegex';
|
|
206
|
+
type DateOperator = 'gte' | 'gt' | 'lte' | 'lt' | 'between';
|
|
207
|
+
interface InternalFilter {
|
|
208
|
+
dimension: Dimension | QueryParamName;
|
|
209
|
+
operator: FilterOperator | DateOperator;
|
|
210
|
+
expression: string;
|
|
211
|
+
expression2?: string;
|
|
212
|
+
}
|
|
213
|
+
declare const FilterBrand: unique symbol;
|
|
214
|
+
interface Filter<C = object> {
|
|
215
|
+
readonly [FilterBrand]: true;
|
|
216
|
+
readonly _constraints: C;
|
|
217
|
+
readonly _filters: InternalFilter[];
|
|
218
|
+
readonly _nestedGroups?: Filter<any>[];
|
|
219
|
+
readonly _groupType?: 'and' | 'or';
|
|
220
|
+
}
|
|
221
|
+
type GSCRow<D extends Dimension[], C> = { [K in D[number]]: K extends keyof C ? C[K] : DimensionValueMap[K] } & {
|
|
222
|
+
clicks: number;
|
|
223
|
+
impressions: number;
|
|
224
|
+
ctr: number;
|
|
225
|
+
position: number;
|
|
226
|
+
};
|
|
227
|
+
interface BuilderState {
|
|
228
|
+
dimensions: Dimension[];
|
|
229
|
+
filter?: Filter<any>;
|
|
230
|
+
rowLimit?: number;
|
|
231
|
+
startRow?: number;
|
|
232
|
+
}
|
|
233
|
+
//#endregion
|
|
234
|
+
//#region src/query/builder.d.ts
|
|
235
|
+
interface GSCQueryBuilder<D extends Dimension[] = [], C = object> {
|
|
236
|
+
select: <T extends Dimension[]>(...dims: T) => GSCQueryBuilder<T, C>;
|
|
237
|
+
where: <F extends Filter<any>>(filter: F) => GSCQueryBuilder<D, C & F['_constraints']>;
|
|
238
|
+
limit: (n: number) => GSCQueryBuilder<D, C>;
|
|
239
|
+
offset: (n: number) => GSCQueryBuilder<D, C>;
|
|
240
|
+
toBody: () => SearchAnalyticsQuery;
|
|
241
|
+
getState: () => BuilderState;
|
|
242
|
+
}
|
|
243
|
+
//#endregion
|
|
244
|
+
//#region src/core/client.d.ts
|
|
245
|
+
interface GoogleSearchConsoleClient {
|
|
246
|
+
/** Query search analytics with builder, returns async generator yielding typed row batches */
|
|
247
|
+
query: <D extends Dimension[], C>(siteUrl: string, builder: GSCQueryBuilder<D, C>) => AsyncGenerator<GSCRow<D, C>[]>;
|
|
248
|
+
/** List all sites */
|
|
249
|
+
sites: () => Promise<ApiSite[]>;
|
|
250
|
+
/** Inspect a URL */
|
|
251
|
+
inspect: (siteUrl: string, url: string) => Promise<InspectUrlIndexResponse>;
|
|
252
|
+
/** Sitemap operations */
|
|
253
|
+
sitemaps: {
|
|
254
|
+
list: (siteUrl: string) => Promise<ApiSitemap[]>;
|
|
255
|
+
get: (siteUrl: string, feedpath: string) => Promise<ApiSitemap>;
|
|
256
|
+
submit: (siteUrl: string, feedpath: string) => Promise<void>;
|
|
257
|
+
delete: (siteUrl: string, feedpath: string) => Promise<void>;
|
|
258
|
+
};
|
|
259
|
+
/** Indexing API operations */
|
|
260
|
+
indexing: {
|
|
261
|
+
publish: (url: string, type: 'URL_UPDATED' | 'URL_DELETED') => Promise<PublishUrlNotificationResponse>;
|
|
262
|
+
getMetadata: (url: string) => Promise<UrlNotificationMetadata>;
|
|
263
|
+
};
|
|
264
|
+
/** @internal */
|
|
265
|
+
_rawQuery: (siteUrl: string, body: SearchAnalyticsQuery) => Promise<SearchAnalyticsResponse>;
|
|
266
|
+
}
|
|
267
|
+
//#endregion
|
|
268
|
+
//#region src/analysis/movers.d.ts
|
|
269
|
+
type MoversSortMetric = 'clicks' | 'impressions' | 'clicksChange' | 'impressionsChange' | 'positionChange';
|
|
270
|
+
interface MoversOptions {
|
|
271
|
+
/** Minimum change threshold to flag. Default: 0.2 (20%) */
|
|
272
|
+
changeThreshold?: number;
|
|
273
|
+
/** Minimum impressions in recent period. Default: 50 */
|
|
274
|
+
minImpressions?: number;
|
|
275
|
+
/** Metric to sort results by. Default: clicksChange */
|
|
276
|
+
sortBy?: MoversSortMetric;
|
|
277
|
+
}
|
|
278
|
+
interface MoversInput {
|
|
279
|
+
current: KeywordRow[];
|
|
280
|
+
previous: KeywordRow[];
|
|
281
|
+
/** If periods have different lengths, provide normalization factor (previous/current) */
|
|
282
|
+
normalizationFactor?: number;
|
|
283
|
+
}
|
|
284
|
+
interface MoverData {
|
|
285
|
+
keyword: string;
|
|
286
|
+
page: string | null;
|
|
287
|
+
recentClicks: number;
|
|
288
|
+
recentImpressions: number;
|
|
289
|
+
recentPosition: number;
|
|
290
|
+
baselineClicks: number;
|
|
291
|
+
baselineImpressions: number;
|
|
292
|
+
baselinePosition: number;
|
|
293
|
+
clicksChange: number;
|
|
294
|
+
clicksChangePercent: number;
|
|
295
|
+
impressionsChangePercent: number;
|
|
296
|
+
positionChange: number;
|
|
297
|
+
}
|
|
298
|
+
interface MoversResult {
|
|
299
|
+
rising: MoverData[];
|
|
300
|
+
declining: MoverData[];
|
|
301
|
+
stable: MoverData[];
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Identifies movers and shakers - keywords with significant recent changes.
|
|
305
|
+
*/
|
|
306
|
+
declare function analyzeMovers(input: MoversInput, options?: MoversOptions): MoversResult;
|
|
307
|
+
//#endregion
|
|
308
|
+
//#region src/analysis/opportunity.d.ts
|
|
309
|
+
type OpportunitySortMetric = 'opportunityScore' | 'potentialClicks' | 'impressions' | 'position';
|
|
310
|
+
interface OpportunityWeights {
|
|
311
|
+
position?: number;
|
|
312
|
+
impressions?: number;
|
|
313
|
+
ctrGap?: number;
|
|
314
|
+
}
|
|
315
|
+
interface OpportunityOptions {
|
|
316
|
+
/** Minimum impressions to consider. Default: 100 */
|
|
317
|
+
minImpressions?: number;
|
|
318
|
+
/** Custom weights for score factors. Default: all 1 */
|
|
319
|
+
weights?: OpportunityWeights;
|
|
320
|
+
/** Sort metric. Default: opportunityScore */
|
|
321
|
+
sortBy?: OpportunitySortMetric;
|
|
322
|
+
}
|
|
323
|
+
interface OpportunityFactors {
|
|
324
|
+
positionScore: number;
|
|
325
|
+
impressionScore: number;
|
|
326
|
+
ctrGapScore: number;
|
|
327
|
+
}
|
|
328
|
+
interface OpportunityResult {
|
|
329
|
+
keyword: string;
|
|
330
|
+
page: string | null;
|
|
331
|
+
clicks: number;
|
|
332
|
+
impressions: number;
|
|
333
|
+
ctr: number;
|
|
334
|
+
position: number;
|
|
335
|
+
opportunityScore: number;
|
|
336
|
+
potentialClicks: number;
|
|
337
|
+
factors: OpportunityFactors;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Scores keywords by optimization opportunity.
|
|
341
|
+
* Composite score combining position, impressions, and CTR gap factors.
|
|
342
|
+
*/
|
|
343
|
+
declare function analyzeOpportunity(keywords: KeywordRow[], options?: OpportunityOptions): OpportunityResult[];
|
|
344
|
+
//#endregion
|
|
345
|
+
//#region src/analysis/seasonality.d.ts
|
|
346
|
+
type SeasonalityMetric = 'clicks' | 'impressions';
|
|
347
|
+
interface SeasonalityOptions {
|
|
348
|
+
/** Metric to analyze for seasonality. Default: clicks */
|
|
349
|
+
metric?: SeasonalityMetric;
|
|
350
|
+
}
|
|
351
|
+
interface MonthlyData {
|
|
352
|
+
month: string;
|
|
353
|
+
value: number;
|
|
354
|
+
vsAverage: number;
|
|
355
|
+
isPeak: boolean;
|
|
356
|
+
isTrough: boolean;
|
|
357
|
+
}
|
|
358
|
+
interface SeasonalityResult {
|
|
359
|
+
hasSeasonality: boolean;
|
|
360
|
+
/** Coefficient of variation: std dev / mean. Higher = more seasonal. */
|
|
361
|
+
strength: number;
|
|
362
|
+
peakMonths: string[];
|
|
363
|
+
troughMonths: string[];
|
|
364
|
+
monthlyBreakdown: MonthlyData[];
|
|
365
|
+
insufficientData: boolean;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Detects seasonality patterns by analyzing monthly traffic variation.
|
|
369
|
+
*/
|
|
370
|
+
declare function analyzeSeasonality(dates: DateRow[], options?: SeasonalityOptions): SeasonalityResult;
|
|
371
|
+
//#endregion
|
|
372
|
+
//#region src/analysis/striking-distance.d.ts
|
|
373
|
+
type StrikingDistanceSortMetric = 'clicks' | 'impressions' | 'ctr' | 'position' | 'potentialClicks';
|
|
374
|
+
interface StrikingDistanceOptions {
|
|
375
|
+
/** Minimum position (inclusive). Default: 4 */
|
|
376
|
+
minPosition?: number;
|
|
377
|
+
/** Maximum position (inclusive). Default: 20 */
|
|
378
|
+
maxPosition?: number;
|
|
379
|
+
/** Minimum impressions. Default: 100 */
|
|
380
|
+
minImpressions?: number;
|
|
381
|
+
/** Maximum CTR (queries with low CTR have more potential). Default: 0.05 (5%) */
|
|
382
|
+
maxCtr?: number;
|
|
383
|
+
/** Sort metric. Default: potentialClicks */
|
|
384
|
+
sortBy?: StrikingDistanceSortMetric;
|
|
385
|
+
/** Sort order. Default: desc */
|
|
386
|
+
sortOrder?: SortOrder;
|
|
387
|
+
}
|
|
388
|
+
interface StrikingDistanceResult {
|
|
389
|
+
keyword: string;
|
|
390
|
+
page: string | null;
|
|
391
|
+
clicks: number;
|
|
392
|
+
impressions: number;
|
|
393
|
+
ctr: number;
|
|
394
|
+
position: number;
|
|
395
|
+
/** Estimated clicks if position improved to top 3 */
|
|
396
|
+
potentialClicks: number;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Finds striking distance keywords - high impressions, low CTR, position 4-20.
|
|
400
|
+
* These are "quick wins" that could gain significant traffic with small ranking improvements.
|
|
401
|
+
*/
|
|
402
|
+
declare function analyzeStrikingDistance(keywords: KeywordRow[], options?: StrikingDistanceOptions): StrikingDistanceResult[];
|
|
403
|
+
//#endregion
|
|
404
|
+
//#region src/analysis/fetch.d.ts
|
|
405
|
+
interface AnalysisPeriod {
|
|
406
|
+
startDate: string;
|
|
407
|
+
endDate: string;
|
|
408
|
+
}
|
|
409
|
+
interface ComparisonPeriod {
|
|
410
|
+
current: AnalysisPeriod;
|
|
411
|
+
previous: AnalysisPeriod;
|
|
412
|
+
}
|
|
413
|
+
type QueryDimension = 'keywords' | 'pages' | 'dates';
|
|
414
|
+
interface QueryOptions {
|
|
415
|
+
/** Dimension to query. Default: keywords */
|
|
416
|
+
dimension?: QueryDimension;
|
|
417
|
+
/** Max rows to fetch. Default: 25000 */
|
|
418
|
+
limit?: number;
|
|
419
|
+
}
|
|
420
|
+
interface QueryResult {
|
|
421
|
+
keywords: KeywordRow[];
|
|
422
|
+
pages: PageRow[];
|
|
423
|
+
dates: DateRow[];
|
|
424
|
+
}
|
|
425
|
+
interface ComparisonQueryResult {
|
|
426
|
+
current: QueryResult;
|
|
427
|
+
previous: QueryResult;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Query search analytics data for a single period.
|
|
431
|
+
* Returns keywords, pages, and dates data.
|
|
432
|
+
* API calls: 3 (one per dimension)
|
|
433
|
+
*/
|
|
434
|
+
declare function queryAnalytics(client: GoogleSearchConsoleClient, siteUrl: string, period: AnalysisPeriod, options?: QueryOptions): Promise<QueryResult>;
|
|
435
|
+
/**
|
|
436
|
+
* Query search analytics data for current and previous periods.
|
|
437
|
+
* Returns comparison data for all dimensions.
|
|
438
|
+
* API calls: 6 (3 per period)
|
|
439
|
+
*/
|
|
440
|
+
declare function queryComparison(client: GoogleSearchConsoleClient, siteUrl: string, periods: ComparisonPeriod, options?: QueryOptions): Promise<ComparisonQueryResult>;
|
|
441
|
+
/**
|
|
442
|
+
* Fetch keywords and analyze striking distance opportunities.
|
|
443
|
+
* API calls: 1
|
|
444
|
+
*/
|
|
445
|
+
declare function fetchStrikingDistance(client: GoogleSearchConsoleClient, siteUrl: string, period: AnalysisPeriod, options?: StrikingDistanceOptions): Promise<StrikingDistanceResult[]>;
|
|
446
|
+
/**
|
|
447
|
+
* Fetch keywords and analyze optimization opportunities.
|
|
448
|
+
* API calls: 1
|
|
449
|
+
*/
|
|
450
|
+
declare function fetchOpportunity(client: GoogleSearchConsoleClient, siteUrl: string, period: AnalysisPeriod, options?: OpportunityOptions): Promise<OpportunityResult[]>;
|
|
451
|
+
/**
|
|
452
|
+
* Fetch keywords and analyze brand vs non-brand segmentation.
|
|
453
|
+
* API calls: 1
|
|
454
|
+
*/
|
|
455
|
+
declare function fetchBrandSegmentation(client: GoogleSearchConsoleClient, siteUrl: string, period: AnalysisPeriod, options: BrandSegmentationOptions): Promise<BrandSegmentationResult>;
|
|
456
|
+
/**
|
|
457
|
+
* Fetch pages and analyze traffic concentration.
|
|
458
|
+
* API calls: 1
|
|
459
|
+
*/
|
|
460
|
+
declare function fetchPageConcentration(client: GoogleSearchConsoleClient, siteUrl: string, period: AnalysisPeriod, options?: ConcentrationOptions): Promise<ConcentrationResult>;
|
|
461
|
+
/**
|
|
462
|
+
* Fetch keywords and analyze traffic concentration.
|
|
463
|
+
* API calls: 1
|
|
464
|
+
*/
|
|
465
|
+
declare function fetchKeywordConcentration(client: GoogleSearchConsoleClient, siteUrl: string, period: AnalysisPeriod, options?: ConcentrationOptions): Promise<ConcentrationResult>;
|
|
466
|
+
/**
|
|
467
|
+
* Fetch keywords and analyze clusters.
|
|
468
|
+
* API calls: 1
|
|
469
|
+
*/
|
|
470
|
+
declare function fetchClustering(client: GoogleSearchConsoleClient, siteUrl: string, period: AnalysisPeriod, options?: ClusteringOptions): Promise<ClusteringResult>;
|
|
471
|
+
/**
|
|
472
|
+
* Fetch dates and analyze seasonality patterns.
|
|
473
|
+
* API calls: 1
|
|
474
|
+
*/
|
|
475
|
+
declare function fetchSeasonality(client: GoogleSearchConsoleClient, siteUrl: string, period: AnalysisPeriod, options?: SeasonalityOptions): Promise<SeasonalityResult>;
|
|
476
|
+
/**
|
|
477
|
+
* Fetch pages for both periods and analyze content decay.
|
|
478
|
+
* API calls: 2
|
|
479
|
+
*/
|
|
480
|
+
declare function fetchDecay(client: GoogleSearchConsoleClient, siteUrl: string, periods: ComparisonPeriod, options?: DecayOptions): Promise<DecayResult[]>;
|
|
481
|
+
/**
|
|
482
|
+
* Fetch keywords for both periods and analyze movers/shakers.
|
|
483
|
+
* API calls: 2
|
|
484
|
+
*/
|
|
485
|
+
declare function fetchMovers(client: GoogleSearchConsoleClient, siteUrl: string, periods: ComparisonPeriod, options?: MoversOptions): Promise<MoversResult>;
|
|
486
|
+
//#endregion
|
|
487
|
+
export { type AnalysisPeriod, type BaseMetrics, type BrandSegmentationOptions, type BrandSegmentationResult, type BrandSummary, type ClusterType, type ClusteringOptions, type ClusteringResult, type ComparisonPeriod, type ComparisonQueryResult, type ConcentrationInput, type ConcentrationItem, type ConcentrationOptions, type ConcentrationResult, type ConcentrationRiskLevel, type DateRow, type DecayInput, type DecayOptions, type DecayResult, type DecaySortMetric, type KeywordCluster, type KeywordRow, type MonthlyData, type MoverData, type MoversInput, type MoversOptions, type MoversResult, type MoversSortMetric, type OpportunityFactors, type OpportunityOptions, type OpportunityResult, type OpportunitySortMetric, type OpportunityWeights, type PageRow, type QueryDimension, type QueryOptions, type QueryResult, type SeasonalityMetric, type SeasonalityOptions, type SeasonalityResult, type SortOrder, type StrikingDistanceOptions, type StrikingDistanceResult, type StrikingDistanceSortMetric, analyzeBrandSegmentation, analyzeClustering, analyzeConcentration, analyzeDecay, analyzeKeywordConcentration, analyzeMovers, analyzeOpportunity, analyzePageConcentration, analyzeSeasonality, analyzeStrikingDistance, createSorter, fetchBrandSegmentation, fetchClustering, fetchDecay, fetchKeywordConcentration, fetchMovers, fetchOpportunity, fetchPageConcentration, fetchSeasonality, fetchStrikingDistance, num, queryAnalytics, queryComparison };
|