Skip to content

Commit 4c03272

Browse files
committed
Merge remote-tracking branch 'upstream/main' into antoinekm/force-reindex
2 parents fc0051d + b3ccccc commit 4c03272

File tree

9 files changed

+121
-35
lines changed

9 files changed

+121
-35
lines changed

.changeset/nervous-carrots-complain.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.changeset/orange-badgers-accept.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
11
# google-indexing-script
22

3+
## 0.2.0
4+
5+
### Minor Changes
6+
7+
- [#62](https://github.com/goenning/google-indexing-script/pull/62) [`93dd956`](https://github.com/goenning/google-indexing-script/commit/93dd956dca4065b97d6076db772560fba57aec50) Thanks [@hasanafzal8485](https://github.com/hasanafzal8485)! - Don't want the same URL use my API limit again until his previous cache limit is completed
8+
9+
## 0.1.0
10+
11+
### Minor Changes
12+
13+
- [#55](https://github.com/goenning/google-indexing-script/pull/55) [`908938a`](https://github.com/goenning/google-indexing-script/commit/908938a701d964b75331e322fbea8d77e6db976e) Thanks [@AntoineKM](https://github.com/AntoineKM)! - feat(get-publish-metadata): optional retries if rate limited
14+
15+
## 0.0.5
16+
17+
### Patch Changes
18+
19+
- [#44](https://github.com/goenning/google-indexing-script/pull/44) [`77b94ed`](https://github.com/goenning/google-indexing-script/commit/77b94edeef863721c07bd3e12d6d38052723f422) Thanks [@AntoineKM](https://github.com/AntoineKM)! - Add site url checker
20+
21+
## 0.0.4
22+
23+
### Patch Changes
24+
25+
- [#40](https://github.com/goenning/google-indexing-script/pull/40) [`074f2c7`](https://github.com/goenning/google-indexing-script/commit/074f2c7ebbafff3a03ebf07baf7b21922a98698d) Thanks [@AntoineKM](https://github.com/AntoineKM)! - Add documentation comments
26+
327
## 0.0.3
428

529
### Patch Changes

CONTRIBUTING.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,10 @@ After making your changes, you can build the project with the following command:
3434

3535
```bash
3636
npm run build
37-
```
37+
```
38+
39+
# Pull Request
40+
41+
1. Make sure your code is formatted with `prettier`
42+
2. Make sure your code passes the tests
43+
3. Make sure you added the changes with `npm run changeset`

README.md

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ Use this script to get your entire site indexed on Google in less than 48 hours.
44

55
You can read more about the motivation behind it and how it works in this blog post https://seogets.com/blog/google-indexing-script
66

7-
> [!IMPORTANT]
7+
> [!IMPORTANT]
8+
>
89
> 1. Indexing != Ranking. This will not help your page rank on Google, it'll just let Google know about the existence of your pages.
910
> 2. This script uses [Google Indexing API](https://developers.google.com/search/apis/indexing-api/v3/quickstart). We do not recommend using this script on spam/low-quality content.
1011
@@ -70,8 +71,6 @@ gis <domain or url>
7071
gis seogets.com
7172
```
7273

73-
When in doubt try both 😀
74-
7574
Here are some other ways to run the script:
7675

7776
```bash
@@ -82,6 +81,7 @@ google-indexing-script seogets.com
8281
# cloned repository
8382
npm run index seogets.com
8483
```
84+
8585
</details>
8686

8787
<details>
@@ -94,6 +94,7 @@ Run the script with the domain or url you want to index.
9494
```bash
9595
GIS_CLIENT_EMAIL=your-client-email GIS_PRIVATE_KEY=your-private-key gis seogets.com
9696
```
97+
9798
</details>
9899

99100
<details>
@@ -106,6 +107,7 @@ Once you have the values, run the script with the domain or url you want to inde
106107
```bash
107108
gis seogets.com --client-email your-client-email --private-key your-private-key
108109
```
110+
109111
</details>
110112

111113
<details>
@@ -118,29 +120,68 @@ npm i google-indexing-script
118120
```
119121

120122
```javascript
121-
import { index } from 'google-indexing-script'
122-
import serviceAccount from './service_account.json'
123+
import { index } from "google-indexing-script";
124+
import serviceAccount from "./service_account.json";
123125

124-
index('seogets.com', {
126+
index("seogets.com", {
125127
client_email: serviceAccount.client_email,
126-
private_key: serviceAccount.private_key
128+
private_key: serviceAccount.private_key,
127129
})
128130
.then(console.log)
129-
.catch(console.error)
131+
.catch(console.error);
130132
```
131133

132134
Read the [API documentation](https://paka.dev/npm/google-indexing-script) for more details.
135+
133136
</details>
134137

135138
Here's an example of what you should expect:
136139

137140
![](./output.png)
138141

139142
> [!IMPORTANT]
143+
>
140144
> - Your site must have 1 or more sitemaps submitted to Google Search Console. Otherwise, the script will not be able to find the pages to index.
141145
> - You can run the script as many times as you want. It will only index the pages that are not already indexed.
142146
> - Sites with a large number of pages might take a while to index, be patient.
143147
148+
## Quota
149+
150+
Depending on your account several quotas are configured for the API (see [docs](https://developers.google.com/search/apis/indexing-api/v3/quota-pricing#quota)). By default the script exits as soon as the rate limit is exceeded. You can configure a retry mechanism for the read requests that apply on a per minute time frame.
151+
152+
<details>
153+
<summary>With environment variables</summary>
154+
155+
```bash
156+
export GIS_QUOTA_RPM_RETRY=true
157+
```
158+
159+
</details>
160+
161+
<details>
162+
<summary>As a npm module</summary>
163+
164+
```javascript
165+
import { index } from 'google-indexing-script'
166+
import serviceAccount from './service_account.json'
167+
168+
index('seogets.com', {
169+
client_email: serviceAccount.client_email,
170+
private_key: serviceAccount.private_key
171+
quota: {
172+
rpmRetry: true
173+
}
174+
})
175+
.then(console.log)
176+
.catch(console.error)
177+
```
178+
179+
</details>
180+
181+
## 🔀 Alternative
182+
183+
If you prefer a hands-free, and less technical solution, you can use a SaaS platform like [TagParrot](https://tagparrot.com/?via=goenning).
184+
144185
## 📄 License
145186

146187
MIT License

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "google-indexing-script",
3-
"version": "0.0.3",
3+
"version": "0.2.0",
44
"main": "./dist/index.js",
55
"types": "./dist/index.d.ts",
66
"bin": {

src/index.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,29 @@ import { readFileSync, existsSync, mkdirSync, writeFileSync } from "fs";
1515
import path from "path";
1616

1717
const CACHE_TIMEOUT = 1000 * 60 * 60 * 24 * 14; // 14 days
18+
export const QUOTA = {
19+
rpm: {
20+
retries: 3,
21+
waitingTime: 60000, // 1 minute
22+
},
23+
};
1824

1925
export type IndexOptions = {
2026
client_email?: string;
2127
private_key?: string;
2228
path?: string;
2329
urls?: string[];
30+
quota?: {
31+
rpmRetry?: boolean; // read requests per minute: retry after waiting time
32+
};
2433
};
2534

2635
/**
2736
* Indexes the specified domain or site URL.
2837
* @param input - The domain or site URL to index.
2938
* @param options - (Optional) Additional options for indexing.
3039
*/
31-
export const index = async (
32-
input: string = process.argv[2],
33-
options: IndexOptions = {},
34-
) => {
40+
export const index = async (input: string = process.argv[2], options: IndexOptions = {}) => {
3541
if (!input) {
3642
console.error("❌ Please provide a domain or site URL as the first argument.");
3743
console.error("");
@@ -50,6 +56,10 @@ export const index = async (
5056
}
5157
if (!options.urls) {
5258
options.urls = args["urls"] ? args["urls"].split(",") : undefined;
59+
if (!options.quota) {
60+
options.quota = {
61+
rpmRetry: args["rpm-retry"] === "true" || process.env.GIS_QUOTA_RPM_RETRY === "true",
62+
};
5363
}
5464

5565
const accessToken = await getAccessToken(options.client_email, options.private_key, options.path);
@@ -108,7 +118,7 @@ export const index = async (
108118
const shouldRecheck = (status: Status, lastCheckedAt: string) => {
109119
const shouldIndexIt = indexableStatuses.includes(status);
110120
const isOld = new Date(lastCheckedAt) < new Date(Date.now() - CACHE_TIMEOUT);
111-
return shouldIndexIt || isOld;
121+
return shouldIndexIt && isOld;;
112122
};
113123

114124
await batch(
@@ -155,7 +165,9 @@ export const index = async (
155165

156166
for (const url of indexablePages) {
157167
console.log(`📄 Processing url: ${url}`);
158-
const status = await getPublishMetadata(accessToken, url);
168+
const status = await getPublishMetadata(accessToken, url, {
169+
retriesOnRateLimit: options.quota.rpmRetry ? QUOTA.rpm.retries : 0,
170+
});
159171
if (status === 404) {
160172
await requestIndexing(accessToken, url);
161173
console.log("🚀 Indexing requested successfully. It may take a few days for Google to process it.");

src/shared/gsc.ts

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { webmasters_v3 } from "googleapis";
2+
import { QUOTA } from "..";
23
import { Status } from "./types";
34
import { fetchRetry } from "./utils";
45

@@ -20,7 +21,7 @@ export function convertToSiteUrl(input: string) {
2021
* @returns The converted file path
2122
*/
2223
export function convertToFilePath(path: string) {
23-
return path.replace("http://", "http_").replace("https://", "https_").replace("/", "_");
24+
return path.replace("http://", "http_").replace("https://", "https_").replaceAll("/", "_");
2425
}
2526

2627
/**
@@ -202,9 +203,10 @@ export function getEmojiForStatus(status: Status) {
202203
* Retrieves metadata for publishing from the given URL.
203204
* @param accessToken - The access token for authentication.
204205
* @param url - The URL for which to retrieve metadata.
206+
* @param options - The options for the request.
205207
* @returns The status of the request.
206208
*/
207-
export async function getPublishMetadata(accessToken: string, url: string) {
209+
export async function getPublishMetadata(accessToken: string, url: string, options?: { retriesOnRateLimit: number }) {
208210
const response = await fetchRetry(
209211
`https://indexing.googleapis.com/v3/urlNotifications/metadata?url=${encodeURIComponent(url)}`,
210212
{
@@ -223,12 +225,23 @@ export async function getPublishMetadata(accessToken: string, url: string) {
223225
}
224226

225227
if (response.status === 429) {
226-
console.error("🚦 Rate limit exceeded, try again later.");
227-
console.error("");
228-
console.error(" Quota: https://developers.google.com/search/apis/indexing-api/v3/quota-pricing#quota");
229-
console.error(" Usage: https://console.cloud.google.com/apis/enabled");
230-
console.error("");
231-
process.exit(1);
228+
if (options?.retriesOnRateLimit && options?.retriesOnRateLimit > 0) {
229+
const RPM_WATING_TIME = (QUOTA.rpm.retries - options.retriesOnRateLimit + 1) * QUOTA.rpm.waitingTime; // increase waiting time for each retry
230+
console.log(
231+
`🚦 Rate limit exceeded for read requests. Retries left: ${options.retriesOnRateLimit}. Waiting for ${
232+
RPM_WATING_TIME / 1000
233+
}sec.`
234+
);
235+
await new Promise((resolve) => setTimeout(resolve, RPM_WATING_TIME));
236+
await getPublishMetadata(accessToken, url, { retriesOnRateLimit: options.retriesOnRateLimit - 1 });
237+
} else {
238+
console.error("🚦 Rate limit exceeded, try again later.");
239+
console.error("");
240+
console.error(" Quota: https://developers.google.com/search/apis/indexing-api/v3/quota-pricing#quota");
241+
console.error(" Usage: https://console.cloud.google.com/apis/enabled");
242+
console.error("");
243+
process.exit(1);
244+
}
232245
}
233246

234247
if (response.status >= 500) {

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"compilerOptions": {
33
"target": "esnext",
44
"module": "commonjs",
5-
"lib": ["dom", "es6", "es2017", "esnext.asynciterable"],
5+
"lib": ["dom", "es6", "es2021", "esnext.asynciterable"],
66
"skipLibCheck": true,
77
"sourceMap": true,
88
"outDir": "./dist",

0 commit comments

Comments
 (0)