@adobe/spacecat-shared-ahrefs-client 1.9.12 → 1.10.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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # [@adobe/spacecat-shared-ahrefs-client-v1.10.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-ahrefs-client-v1.9.13...@adobe/spacecat-shared-ahrefs-client-v1.10.0) (2025-11-13)
2
+
3
+
4
+ ### Features
5
+
6
+ * (ahref) add endpoints with paid data ([#1119](https://github.com/adobe/spacecat-shared/issues/1119)) ([cc2abb0](https://github.com/adobe/spacecat-shared/commit/cc2abb058a5686fffb1040a2243452160330b086))
7
+
8
+ # [@adobe/spacecat-shared-ahrefs-client-v1.9.13](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-ahrefs-client-v1.9.12...@adobe/spacecat-shared-ahrefs-client-v1.9.13) (2025-11-04)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **deps:** update dependency @adobe/helix-universal to v5.3.0 ([#1091](https://github.com/adobe/spacecat-shared/issues/1091)) ([13cbc72](https://github.com/adobe/spacecat-shared/commit/13cbc721f67c066948337faa6c6a4ea5b0c5ec9a))
14
+
1
15
  # [@adobe/spacecat-shared-ahrefs-client-v1.9.12](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-ahrefs-client-v1.9.11...@adobe/spacecat-shared-ahrefs-client-v1.9.12) (2025-10-28)
2
16
 
3
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-ahrefs-client",
3
- "version": "1.9.12",
3
+ "version": "1.10.0",
4
4
  "description": "Shared modules of the Spacecat Services - Ahrefs Client",
5
5
  "type": "module",
6
6
  "engines": {
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@adobe/fetch": "4.2.3",
38
- "@adobe/helix-universal": "5.2.3",
38
+ "@adobe/helix-universal": "5.3.0",
39
39
  "@adobe/spacecat-shared-utils": "1.66.0"
40
40
  },
41
41
  "devDependencies": {
package/src/index.d.ts CHANGED
@@ -84,4 +84,29 @@ export default class AhrefsAPIClient {
84
84
  excludeBranded?: boolean,
85
85
  }):
86
86
  Promise<{ result: object, fullAuditRef: string }>;
87
+
88
+ /**
89
+ * Asynchronous method to get paid pages for a URL.
90
+ * @param url - The target URL
91
+ * @param date - Optional date in YYYY-MM-DD format, defaults to today
92
+ * @param limit - Maximum number of results to return (max: 1000)
93
+ */
94
+ getPaidPages(url: string, date?: string, limit?: number):
95
+ Promise<{ result: object, fullAuditRef: string }>;
96
+
97
+ /**
98
+ * Asynchronous method to get metrics for a URL.
99
+ * @param url - The target URL
100
+ * @param date - Optional date in YYYY-MM-DD format, defaults to today
101
+ */
102
+ getMetrics(url: string, date?: string):
103
+ Promise<{ result: object, fullAuditRef: string }>;
104
+
105
+ /**
106
+ * Asynchronous method to get metrics by country for a URL.
107
+ * @param url - The target URL
108
+ * @param date - Optional date in YYYY-MM-DD format, defaults to today
109
+ */
110
+ getMetricsByCountry(url: string, date?: string):
111
+ Promise<{ result: object, fullAuditRef: string }>;
87
112
  }
package/src/index.js CHANGED
@@ -38,6 +38,17 @@ export const ORGANIC_KEYWORDS_FIELDS = /** @type {const} */ ([
38
38
  'serp_features',
39
39
  ]);
40
40
 
41
+ export const METRICS_BY_COUNTRY_FILTER_FIELDS = /** @type {const} */ ([
42
+ 'org_keywords',
43
+ 'paid_keywords',
44
+ 'org_keywords_1_3',
45
+ 'org_traffic',
46
+ 'org_cost',
47
+ 'paid_traffic',
48
+ 'paid_cost',
49
+ 'paid_pages',
50
+ ]);
51
+
41
52
  export default class AhrefsAPIClient {
42
53
  static createFrom(context) {
43
54
  const { AHREFS_API_BASE_URL: apiBaseUrl, AHREFS_API_KEY: apiKey } = context.env;
@@ -259,6 +270,139 @@ export default class AhrefsAPIClient {
259
270
  return this.sendRequest('/site-explorer/organic-keywords', queryParams);
260
271
  }
261
272
 
273
+ /**
274
+ * Retrieves pages with paid search traffic for a given URL.
275
+ *
276
+ * @param {string} url - The target URL to analyze
277
+ * @param {string} [date] - The date for the analysis in YYYY-MM-DD format.
278
+ * Defaults to today's date.
279
+ * @param {number} [limit=200] - Maximum number of results to return (max: 1000)
280
+ * @returns {Promise<{result: Object, fullAuditRef: string}>} Response object containing:
281
+ * - result.pages: Array of paid page objects with properties:
282
+ * - url: The page URL
283
+ * - top_keyword: The keyword that brings the most paid traffic to a page.
284
+ * - top_keyword_best_position_title: The title displayed for the page in its top
285
+ * keyword's SERP.
286
+ * - top_keyword_country: The country in which a page ranks for its top keyword
287
+ * - top_keyword_volume: An estimation of the average monthly number of
288
+ * searches for the top keyword over the latest month
289
+ * - sum_traffic: An estimation of the monthly paid search traffic that a page gets from
290
+ * all the keywords that it ranks for.
291
+ * - value: The estimated cost of a page's monthly paid search traffic, in USD cents.
292
+ * - fullAuditRef: Full URL of the API request for reference
293
+ * @example
294
+ * const result = await client.getPaidPages('example.com', '2025-11-10', 50);
295
+ * console.log(result.result.pages); // Array of paid pages
296
+ */
297
+ async getPaidPages(url, date = new Date().toISOString().split('T')[0], limit = 200) {
298
+ const queryParams = {
299
+ target: url,
300
+ date,
301
+ select: [
302
+ 'url',
303
+ 'top_keyword',
304
+ 'top_keyword_best_position_title',
305
+ 'top_keyword_country',
306
+ 'top_keyword_volume',
307
+ 'sum_traffic',
308
+ 'value',
309
+ ].join(','),
310
+ order_by: 'sum_traffic:desc',
311
+ limit: getLimit(limit, 1000),
312
+ output: 'json',
313
+ };
314
+
315
+ return this.sendRequest('/site-explorer/paid-pages', queryParams);
316
+ }
317
+
318
+ /**
319
+ * Retrieves overall metrics for a given target URL.
320
+ *
321
+ * @param {string} url - The target URL to analyze
322
+ * @param {string} [date] - The date for the analysis in YYYY-MM-DD format.
323
+ * Defaults to today's date.
324
+ * @returns {Promise<{result: Object, fullAuditRef: string}>} Response object containing:
325
+ * - result.metrics: Object with overall metrics:
326
+ * - org_keywords: The total number of keywords that your target ranks for in the top 100
327
+ * organic search results.
328
+ * - paid_keywords: The total number of keywords that your target ranks for in paid
329
+ * search results.
330
+ * - org_keywords_1_3: The total number of keywords that your target ranks for in the
331
+ * top 3 organic search results.
332
+ * - org_traffic: The estimated number of monthly visitors that your target gets from
333
+ * organic search.
334
+ * - org_cost: The estimated value of your target's monthly organic search traffic,
335
+ * in USD cents.
336
+ * - paid_traffic: The estimated number of monthly visitors that your target gets from
337
+ * paid search.
338
+ * - paid_cost: The estimated cost of your target's monthly paid search traffic,
339
+ * in USD cents.
340
+ * - paid_pages: The total number of pages from a target ranking in paid search results.
341
+ * - fullAuditRef: Full URL of the API request for reference
342
+ * @example
343
+ * const result = await client.getMetrics('example.com', '2025-11-10');
344
+ * console.log(result.result.metrics.org_traffic); // Organic traffic value
345
+ */
346
+ async getMetrics(url, date = new Date().toISOString().split('T')[0]) {
347
+ const queryParams = {
348
+ target: url,
349
+ date,
350
+ };
351
+
352
+ return this.sendRequest('/site-explorer/metrics', queryParams);
353
+ }
354
+
355
+ /**
356
+ * Retrieves metrics broken down by country for a given target URL.
357
+ * Automatically filters out countries where both organic and paid traffic are zero.
358
+ *
359
+ * @param {string} url - The target URL to analyze
360
+ * @param {string} [date] - The date for the analysis in YYYY-MM-DD format.
361
+ * Defaults to today's date.
362
+ * @returns {Promise<{result: Object, fullAuditRef: string}>} Response object containing:
363
+ * - result.metrics: Array of metric objects, each containing:
364
+ * - country: Two-letter country code (e.g., "US", "IN")
365
+ * - org_keywords: The total number of keywords that your target ranks for in the
366
+ * top 100 organic search results in this country.
367
+ * - paid_keywords: The total number of keywords that your target ranks for in paid
368
+ * search results in this country.
369
+ * - org_keywords_1_3: The total number of keywords that your target ranks for in the
370
+ * top 3 organic search results in this country.
371
+ * - org_traffic: The estimated number of monthly visitors that your target gets from
372
+ * organic search in this country.
373
+ * - org_cost: The estimated value of your target's monthly organic search traffic
374
+ * from this country, in USD cents.
375
+ * - paid_traffic: The estimated number of monthly visitors that your target gets from
376
+ * paid search in this country.
377
+ * - paid_cost: The estimated cost of your target's monthly paid search traffic from
378
+ * this country, in USD cents.
379
+ * - paid_pages: The total number of pages from a target ranking in paid search
380
+ * results in this country.
381
+ * - fullAuditRef: Full URL of the API request for reference
382
+ * @example
383
+ * const result = await client.getMetricsByCountry('example.com', '2025-11-10');
384
+ * console.log(result.result.metrics); // Array of metrics by country (excluding zeros)
385
+ */
386
+ async getMetricsByCountry(url, date = new Date().toISOString().split('T')[0]) {
387
+ const queryParams = {
388
+ target: url,
389
+ date,
390
+ };
391
+
392
+ const response = await this.sendRequest('/site-explorer/metrics-by-country', queryParams);
393
+
394
+ // Filter out countries where all metric values are 0 or null
395
+ if (response.result?.metrics) {
396
+ response.result.metrics = response.result.metrics
397
+ .filter((metric) => METRICS_BY_COUNTRY_FILTER_FIELDS.some((field) => {
398
+ const value = metric[field];
399
+ return value !== null && value !== 0;
400
+ }));
401
+ }
402
+
403
+ return response;
404
+ }
405
+
262
406
  async getLimitsAndUsage() {
263
407
  return this.sendRequest('/subscription-info/limits-and-usage');
264
408
  }