seo-crawl-audit 0.1.2 → 0.7.1
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 +303 -228
- package/bin/seo-audit.js +18 -3
- package/bundle/cli.js +154 -0
- package/package.json +10 -8
- package/examples/quotes-toscrape-report.html +0 -423
- package/src/audit.js +0 -125
- package/src/baseline.js +0 -65
- package/src/checkpoint.js +0 -90
- package/src/cli.js +0 -850
- package/src/compare.js +0 -205
- package/src/crawler.js +0 -306
- package/src/html-report.js +0 -474
- package/src/html.js +0 -105
- package/src/report.js +0 -43
- package/src/request-gate.js +0 -27
- package/src/robots.js +0 -80
- package/src/sitemap.js +0 -212
- package/src/target.js +0 -35
- package/src/urls.js +0 -45
package/README.md
CHANGED
|
@@ -1,48 +1,74 @@
|
|
|
1
1
|
# SEO Crawl Audit
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
account
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
3
|
+
Free, open-source, local-first SEO crawler and regression audit tool.
|
|
4
|
+
|
|
5
|
+
`seo-audit` crawls server-rendered pages, saves a versioned JSON snapshot,
|
|
6
|
+
finds concrete SEO problems, and detects regressions after a deployment. It
|
|
7
|
+
needs no account or API key. Page HTML is processed in memory; normalized
|
|
8
|
+
results stay in local JSON, checkpoint, CSV, and self-contained HTML files.
|
|
9
|
+
|
|
10
|
+
[Open the interactive example report](https://melnixdev.github.io/seo-crawl-audit/)
|
|
11
|
+
or [view its source file](examples/quotes-toscrape-report.html).
|
|
12
|
+
|
|
13
|
+
## Highlights
|
|
14
|
+
|
|
15
|
+
- automatic `robots.txt`, sitemap, sitemap-index, and gzip sitemap support;
|
|
16
|
+
- bounded concurrency with a per-origin request delay;
|
|
17
|
+
- retries for timeouts, `429`, and temporary `5xx`, including `Retry-After`;
|
|
18
|
+
- redirect-chain and redirect-loop detection;
|
|
19
|
+
- 40+ explicit audit and regression rules with stable fingerprints;
|
|
20
|
+
- SnapshotV2 with automatic baseline v1 migration;
|
|
21
|
+
- `new`, `ongoing`, `resolved`, and `unchanged` issue lifecycle;
|
|
22
|
+
- resumable scans and a useful report even after interruption;
|
|
23
|
+
- local SnapshotV2 history with issue, page-count, sitemap, and crawl-depth
|
|
24
|
+
trends—without a hosted account;
|
|
25
|
+
- English/Ukrainian report localization, filters, CSV export, print layout,
|
|
26
|
+
and local report branding;
|
|
27
|
+
- interactive issue statistics for severity, frequent checks, ownership, and
|
|
28
|
+
regression lifecycle, with chart-to-table filtering;
|
|
29
|
+
- a production-versus-preview release guard with safe environment-based
|
|
30
|
+
authentication for private deployments;
|
|
31
|
+
- configuration, suppressions with expiry, severity overrides, and budgets;
|
|
32
|
+
- a self-contained GitHub Action that runs inside the GitHub runner;
|
|
33
|
+
- typed engine API with injectable `fetch`, checkpoints, events, logger, and
|
|
34
|
+
`AbortSignal`.
|
|
35
|
+
|
|
36
|
+
The project intentionally does not calculate an opaque overall SEO score.
|
|
37
|
+
Every finding names the affected URL, rule, risk, evidence, owner, and suggested
|
|
38
|
+
remediation.
|
|
22
39
|
|
|
23
40
|
## Requirements and installation
|
|
24
41
|
|
|
25
42
|
Node.js 20.19 or newer is required.
|
|
26
43
|
|
|
44
|
+
Run without installing:
|
|
45
|
+
|
|
27
46
|
```bash
|
|
28
|
-
|
|
29
|
-
cd seo-crawl-audit
|
|
30
|
-
npm install
|
|
31
|
-
npm link
|
|
47
|
+
npx seo-crawl-audit https://example.com/
|
|
32
48
|
```
|
|
33
49
|
|
|
34
|
-
|
|
50
|
+
Or install the CLI globally:
|
|
35
51
|
|
|
36
52
|
```bash
|
|
53
|
+
npm install --global seo-crawl-audit
|
|
37
54
|
seo-audit --version
|
|
38
|
-
seo-audit --help
|
|
39
55
|
```
|
|
40
56
|
|
|
41
|
-
|
|
57
|
+
For repository development:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
git clone https://github.com/MelnixDev/seo-crawl-audit.git
|
|
61
|
+
cd seo-crawl-audit
|
|
62
|
+
npm install
|
|
63
|
+
npm run build
|
|
64
|
+
npm link --workspace seo-crawl-audit
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Five-minute example
|
|
42
68
|
|
|
43
69
|
[Quotes to Scrape](https://quotes.toscrape.com/) is a public educational site
|
|
44
|
-
made for crawler practice. It is unrelated to this project and keeps the
|
|
45
|
-
small
|
|
70
|
+
made for crawler practice. It is unrelated to this project and keeps the
|
|
71
|
+
example small.
|
|
46
72
|
|
|
47
73
|
```bash
|
|
48
74
|
seo-audit scan https://quotes.toscrape.com/ \
|
|
@@ -52,15 +78,7 @@ seo-audit scan https://quotes.toscrape.com/ \
|
|
|
52
78
|
--report quotes-report.html
|
|
53
79
|
```
|
|
54
80
|
|
|
55
|
-
|
|
56
|
-
HTML report. In the current demo scan, the tool finds missing descriptions and
|
|
57
|
-
canonical URLs while the pages themselves remain reachable.
|
|
58
|
-
|
|
59
|
-
[View the included example report](examples/quotes-toscrape-report.html). GitHub
|
|
60
|
-
may show the HTML source; download the file and open it in any browser to use
|
|
61
|
-
the filters.
|
|
62
|
-
|
|
63
|
-
Run a fresh comparison later:
|
|
81
|
+
Run a comparison later:
|
|
64
82
|
|
|
65
83
|
```bash
|
|
66
84
|
seo-audit check https://quotes.toscrape.com/ \
|
|
@@ -73,7 +91,7 @@ seo-audit check https://quotes.toscrape.com/ \
|
|
|
73
91
|
|
|
74
92
|
### `seo-audit <url>`
|
|
75
93
|
|
|
76
|
-
|
|
94
|
+
Shortcut for `seo-audit scan <url>`.
|
|
77
95
|
|
|
78
96
|
```bash
|
|
79
97
|
seo-audit https://example.com/
|
|
@@ -81,7 +99,8 @@ seo-audit https://example.com/
|
|
|
81
99
|
|
|
82
100
|
### `seo-audit scan <url>`
|
|
83
101
|
|
|
84
|
-
Crawls a site, audits its current
|
|
102
|
+
Crawls a site, audits its current state, saves SnapshotV2, and optionally writes
|
|
103
|
+
an HTML report.
|
|
85
104
|
|
|
86
105
|
```bash
|
|
87
106
|
seo-audit scan https://example.com/
|
|
@@ -89,25 +108,14 @@ seo-audit scan https://example.com/ --pages 250
|
|
|
89
108
|
seo-audit scan https://example.com/ --all
|
|
90
109
|
```
|
|
91
110
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
3. tries `/sitemap.xml` and `/sitemap_index.xml` when needed;
|
|
97
|
-
4. shows an interactive scan-size menu when a sitemap is found;
|
|
98
|
-
5. saves the baseline to `.seo-audit.json`;
|
|
99
|
-
6. creates `seo-audit-report.html` in an interactive terminal.
|
|
100
|
-
|
|
101
|
-
The menu offers the first 100 pages, the whole sitemap, batches of 100 with
|
|
102
|
-
confirmation, or any positive number entered by the user. `--pages` and `--all`
|
|
103
|
-
skip that menu.
|
|
104
|
-
|
|
105
|
-
If no sitemap is found, the interactive command asks for its full URL. Pressing
|
|
106
|
-
Enter instead starts a same-origin internal-link crawl.
|
|
111
|
+
When a sitemap is found in an interactive terminal, the menu offers the first
|
|
112
|
+
100 pages, every sitemap URL, groups of 100 with confirmation, or a custom
|
|
113
|
+
number. `--pages` and `--all` skip the menu. If no sitemap is found, press Enter
|
|
114
|
+
to continue through same-origin internal links, or enter the full sitemap URL.
|
|
107
115
|
|
|
108
116
|
### `seo-audit check [url]`
|
|
109
117
|
|
|
110
|
-
Crawls
|
|
118
|
+
Crawls again and compares the result with a saved baseline.
|
|
111
119
|
|
|
112
120
|
```bash
|
|
113
121
|
seo-audit check
|
|
@@ -115,258 +123,325 @@ seo-audit check https://preview.example.com/
|
|
|
115
123
|
seo-audit check --baseline production-seo.json --strict
|
|
116
124
|
```
|
|
117
125
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
126
|
+
Without `url`, the saved site URL is used. A different origin supports
|
|
127
|
+
production-to-preview comparison while keeping paths comparable. New
|
|
128
|
+
error-level findings return exit code `1`; `--strict` also blocks on warnings.
|
|
129
|
+
If `scan` receives SIGINT or SIGTERM, it flushes completed pages, writes the
|
|
130
|
+
partial snapshot/report, keeps the checkpoint, and exits with code `130`.
|
|
121
131
|
|
|
122
|
-
|
|
123
|
-
`--strict` is enabled.
|
|
132
|
+
### `seo-audit compare`
|
|
124
133
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
Builds a new HTML audit report from an existing baseline without crawling or
|
|
128
|
-
making network requests.
|
|
134
|
+
Scans production, requests the same paths from a preview deployment, and
|
|
135
|
+
reports only SEO regressions introduced by the preview:
|
|
129
136
|
|
|
130
137
|
```bash
|
|
131
|
-
seo-audit
|
|
132
|
-
|
|
133
|
-
|
|
138
|
+
seo-audit compare \
|
|
139
|
+
--production https://example.com/ \
|
|
140
|
+
--preview https://preview-123.example.dev/ \
|
|
141
|
+
--pages 100 \
|
|
142
|
+
--report preview-seo-report.html
|
|
134
143
|
```
|
|
135
144
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
## HTML report
|
|
140
|
-
|
|
141
|
-
The report is one portable HTML file with no external scripts, fonts, tracking,
|
|
142
|
-
or uploaded data. It contains:
|
|
143
|
-
|
|
144
|
-
- summary cards for checked and affected pages;
|
|
145
|
-
- error, warning, and informational issue counts;
|
|
146
|
-
- free-text search across URL, rule, message, before, and after values;
|
|
147
|
-
- severity and rule filters;
|
|
148
|
-
- paginated results with 100, 250, or 500 rows per page;
|
|
149
|
-
- direct links to affected pages;
|
|
150
|
-
- before/after values for regression checks.
|
|
151
|
-
|
|
152
|
-
During an interactive `scan`, the report is created immediately and refreshed
|
|
153
|
-
after the first completed request batch, then periodically as the scan grows.
|
|
154
|
-
Writes are atomic, so interruption should not leave a half-written HTML file.
|
|
155
|
-
A partial report clearly says that it contains saved results and shows
|
|
156
|
-
`checked / target` page counts.
|
|
157
|
-
|
|
158
|
-
Interactive `scan` and `check` commands create the default report automatically.
|
|
159
|
-
For scripts or CI, request one explicitly:
|
|
145
|
+
For a protected deployment, put request headers in an environment variable as
|
|
146
|
+
a JSON object and pass only its name on the command line:
|
|
160
147
|
|
|
161
148
|
```bash
|
|
162
|
-
|
|
163
|
-
seo-audit
|
|
149
|
+
export SEO_AUDIT_PREVIEW_HEADERS='{"Authorization":"Bearer …"}'
|
|
150
|
+
seo-audit compare \
|
|
151
|
+
--production https://example.com/ \
|
|
152
|
+
--preview https://preview-123.example.dev/ \
|
|
153
|
+
--preview-headers-env SEO_AUDIT_PREVIEW_HEADERS
|
|
164
154
|
```
|
|
165
155
|
|
|
166
|
-
|
|
156
|
+
Header values are used only by the injected request adapter. They are never
|
|
157
|
+
written to snapshots, reports, checkpoints, or JSON output. Errors block the
|
|
158
|
+
release with exit code `1`; `--strict` also blocks on warnings.
|
|
167
159
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
`scan` stores completed page results in an append-only checkpoint beside the
|
|
171
|
-
baseline. For the default `.seo-audit.json` output, its name is:
|
|
172
|
-
|
|
173
|
-
```text
|
|
174
|
-
.seo-audit.checkpoint.ndjson
|
|
175
|
-
```
|
|
160
|
+
### `seo-audit report [baseline]`
|
|
176
161
|
|
|
177
|
-
|
|
178
|
-
page HTML. Each completed request batch is appended immediately. If the process
|
|
179
|
-
is stopped, run the same compatible scan command again:
|
|
162
|
+
Regenerates HTML from a saved snapshot without network requests.
|
|
180
163
|
|
|
181
164
|
```bash
|
|
182
|
-
seo-audit
|
|
165
|
+
seo-audit report
|
|
166
|
+
seo-audit report quotes-baseline.json --report quotes-report.html
|
|
183
167
|
```
|
|
184
168
|
|
|
185
|
-
|
|
186
|
-
is reused only when the start URL, sitemap, query-string policy, and robots
|
|
187
|
-
policy match. An incompatible checkpoint is replaced automatically.
|
|
188
|
-
|
|
189
|
-
The checkpoint is removed after the requested scan target finishes. It remains
|
|
190
|
-
when a stepped scan is stopped before its target or when the process is
|
|
191
|
-
interrupted. Checkpoint files are excluded by the included `.gitignore`.
|
|
169
|
+
### `seo-audit history [url]`
|
|
192
170
|
|
|
193
|
-
|
|
171
|
+
Lists locally saved runs and creates an HTML report with issue trends:
|
|
194
172
|
|
|
195
173
|
```bash
|
|
196
|
-
seo-audit https://example.com/
|
|
174
|
+
seo-audit history https://example.com/
|
|
175
|
+
seo-audit history --history-dir ./audit-history --report history.html
|
|
197
176
|
```
|
|
198
177
|
|
|
199
|
-
|
|
200
|
-
observe the current response from every baseline URL.
|
|
178
|
+
Compare any two saved runs without crawling:
|
|
201
179
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
-
|
|
207
|
-
|
|
208
|
-
- pages blocked by `robots.txt`;
|
|
209
|
-
- missing titles;
|
|
210
|
-
- missing meta descriptions;
|
|
211
|
-
- missing canonical URLs;
|
|
212
|
-
- missing or multiple H1 headings;
|
|
213
|
-
- `noindex` directives.
|
|
214
|
-
|
|
215
|
-
The regression check detects:
|
|
216
|
-
|
|
217
|
-
- a previously working page becoming unavailable;
|
|
218
|
-
- a new `noindex` directive;
|
|
219
|
-
- a page becoming blocked by `robots.txt`;
|
|
220
|
-
- a removed or changed title;
|
|
221
|
-
- a removed meta description;
|
|
222
|
-
- a removed or changed canonical URL;
|
|
223
|
-
- a removed H1 heading;
|
|
224
|
-
- a changed redirect destination;
|
|
225
|
-
- a changed `robots.txt`.
|
|
226
|
-
|
|
227
|
-
Errors represent changes or conditions likely to block indexing or make a page
|
|
228
|
-
unusable. Warnings identify important metadata problems. Informational findings
|
|
229
|
-
are worth reviewing but do not fail a normal check.
|
|
180
|
+
```bash
|
|
181
|
+
seo-audit history \
|
|
182
|
+
--from .seo-audit/history/older.snapshot.json \
|
|
183
|
+
--to .seo-audit/history/newer.snapshot.json \
|
|
184
|
+
--report selected-runs.html
|
|
185
|
+
```
|
|
230
186
|
|
|
231
187
|
## Options
|
|
232
188
|
|
|
233
189
|
```text
|
|
234
190
|
--baseline <file> Baseline input for check (default: .seo-audit.json)
|
|
235
|
-
--
|
|
191
|
+
--config <file> Config file (default: seo-audit.config.json)
|
|
192
|
+
--output <file> Snapshot output for scan (default: .seo-audit.json)
|
|
236
193
|
--report <file> HTML report output (default: seo-audit-report.html)
|
|
237
194
|
--no-report Disable automatic HTML report generation
|
|
238
|
-
--no-cache Disable
|
|
195
|
+
--no-cache Disable checkpoint caching and resume
|
|
239
196
|
--pages <number> Scan an exact number of pages
|
|
240
197
|
--all Scan every URL found in the sitemap
|
|
241
198
|
--max-pages <number> Deprecated alias for --pages
|
|
242
199
|
--concurrency <number> Concurrent requests (default: 5)
|
|
243
|
-
--delay <ms> Delay between
|
|
200
|
+
--delay <ms> Delay between starts per origin (default: 100)
|
|
244
201
|
--timeout <ms> Per-request timeout (default: 10000)
|
|
245
202
|
--sitemap <url> Use a specific sitemap or sitemap index
|
|
246
203
|
--no-sitemap Skip sitemap discovery and crawl internal links
|
|
247
204
|
--include-query Treat query-string URLs as separate pages
|
|
248
205
|
--ignore-robots Ignore robots.txt disallow rules
|
|
249
206
|
--strict Fail check on warnings as well as errors
|
|
250
|
-
--
|
|
251
|
-
--
|
|
207
|
+
--production <url> Production URL for compare
|
|
208
|
+
--preview <url> Preview deployment URL for compare
|
|
209
|
+
--production-headers-env <name>
|
|
210
|
+
Read production headers from a JSON environment variable
|
|
211
|
+
--preview-headers-env <name>
|
|
212
|
+
Read preview headers from a JSON environment variable
|
|
213
|
+
--history-dir <path> Local snapshot history directory
|
|
214
|
+
--no-history Do not save this scan to local history
|
|
215
|
+
--from <snapshot> Older snapshot for an explicit history comparison
|
|
216
|
+
--to <snapshot> Newer snapshot for an explicit history comparison
|
|
217
|
+
--json Print machine-readable output
|
|
218
|
+
--help Show help
|
|
252
219
|
--version Show the installed version
|
|
253
220
|
```
|
|
254
221
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
222
|
+
## Configuration
|
|
223
|
+
|
|
224
|
+
The repository includes [`seo-audit.config.json`](seo-audit.config.json) and a
|
|
225
|
+
[JSON Schema](packages/core/config.schema.json). CLI flags take precedence over
|
|
226
|
+
the config file, which takes precedence over the saved baseline, followed by
|
|
227
|
+
safe defaults.
|
|
228
|
+
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"$schema": "./packages/core/config.schema.json",
|
|
232
|
+
"url": "https://example.com/",
|
|
233
|
+
"sitemap": "auto",
|
|
234
|
+
"maxPages": 100,
|
|
235
|
+
"concurrency": 5,
|
|
236
|
+
"delay": 100,
|
|
237
|
+
"timeout": 10000,
|
|
238
|
+
"respectRobots": true,
|
|
239
|
+
"includeQuery": false,
|
|
240
|
+
"enabledRules": null,
|
|
241
|
+
"severityOverrides": {
|
|
242
|
+
"low-word-count": "info"
|
|
243
|
+
},
|
|
244
|
+
"suppressions": [
|
|
245
|
+
{
|
|
246
|
+
"rule": "missing-description",
|
|
247
|
+
"urlPattern": "/legal/**",
|
|
248
|
+
"reason": "Description intentionally omitted",
|
|
249
|
+
"expiresAt": "2027-01-01"
|
|
250
|
+
}
|
|
251
|
+
],
|
|
252
|
+
"regressionBudgets": {
|
|
253
|
+
"error": 0,
|
|
254
|
+
"warning": 3
|
|
255
|
+
},
|
|
256
|
+
"report": {
|
|
257
|
+
"agencyName": "Example Agency",
|
|
258
|
+
"logo": "https://example.com/logo.png",
|
|
259
|
+
"primaryColor": "#3157d5"
|
|
260
|
+
}
|
|
261
|
+
}
|
|
294
262
|
```
|
|
295
263
|
|
|
296
|
-
|
|
264
|
+
Expired suppressions stop matching automatically, so the issue appears again.
|
|
265
|
+
`urlPattern` accepts `*` within one path segment and `**` across segments.
|
|
297
266
|
|
|
298
|
-
##
|
|
267
|
+
## What is checked
|
|
299
268
|
|
|
300
|
-
|
|
301
|
-
|
|
269
|
+
The rule registry covers access and HTTP failures, meta and header `noindex`,
|
|
270
|
+
robots blocking, canonical validity and targets, redirects, sitemap consistency,
|
|
271
|
+
titles, descriptions, headings, internal links, orphan pages, hreflang,
|
|
272
|
+
structured data syntax, language declarations, exact duplicate content, social
|
|
273
|
+
metadata, image alt attributes, and low word count.
|
|
274
|
+
|
|
275
|
+
Regression-only checks cover newly introduced indexing blocks, status changes,
|
|
276
|
+
metadata removal or edits, redirect changes, robots changes, and sharp sitemap
|
|
277
|
+
URL loss.
|
|
278
|
+
|
|
279
|
+
[Read the rule-by-rule documentation](https://github.com/MelnixDev/seo-crawl-audit/blob/main/docs/rules.md) ·
|
|
280
|
+
[Українська версія довідника правил](https://github.com/MelnixDev/seo-crawl-audit/blob/main/docs/rules.uk.md).
|
|
281
|
+
|
|
282
|
+
## Snapshots, lifecycle, and checkpoints
|
|
283
|
+
|
|
284
|
+
SnapshotV2 records schema, engine and rule-set versions, generated time, config
|
|
285
|
+
hash, robots and sitemap state, normalized page data, link-graph summary, and
|
|
286
|
+
crawl statistics. Baseline schema v1 is upgraded automatically when read.
|
|
287
|
+
|
|
288
|
+
Issues use a stable 24-character fingerprint. A comparison separates:
|
|
289
|
+
|
|
290
|
+
- `newIssues` — absent from the previous snapshot;
|
|
291
|
+
- `ongoingIssues` — same issue identity with changed evidence;
|
|
292
|
+
- `resolvedIssues` — present before but absent now;
|
|
293
|
+
- `unchangedIssues` — same identity and evidence.
|
|
294
|
+
|
|
295
|
+
`DiffResult.complete` is `false` for partial or truncated comparisons. Findings
|
|
296
|
+
on checked pages are still reported, while unchecked pages are not falsely
|
|
297
|
+
classified as missing or resolved.
|
|
298
|
+
|
|
299
|
+
During `scan`, completed normalized page results are appended to
|
|
300
|
+
`.seo-audit.checkpoint.ndjson`. Full HTML is not cached. Running the same
|
|
301
|
+
compatible command resumes without requesting saved pages again. The checkpoint
|
|
302
|
+
is removed after completion and retained after interruption. Successful pages
|
|
303
|
+
are reused; transient failures and HTTP 5xx results are refreshed. Only an
|
|
304
|
+
unfinished final NDJSON record is recoverable—earlier corruption is reported.
|
|
305
|
+
|
|
306
|
+
Every completed scan and check also saves a full SnapshotV2 beside the selected
|
|
307
|
+
baseline under `.seo-audit/history/`. Use `--history-dir` to move it or
|
|
308
|
+
`--no-history` for an ephemeral run. History is read directly from disk; no URL,
|
|
309
|
+
snapshot, or metric is uploaded. The HTML trend view shows errors, warnings,
|
|
310
|
+
informational findings, new/resolved issues, page count, sitemap count, and
|
|
311
|
+
maximum crawl depth.
|
|
312
|
+
|
|
313
|
+
## HTML and CSV report
|
|
314
|
+
|
|
315
|
+
The portable HTML file contains no external script, font, or tracking request.
|
|
316
|
+
It includes:
|
|
317
|
+
|
|
318
|
+
- an `English / Українська` language selector that translates the complete
|
|
319
|
+
interface, rule names, findings, remediation, lifecycle labels, and CSV;
|
|
320
|
+
- dependency-free interactive charts for severity, most frequent checks,
|
|
321
|
+
inferred page templates, and owner or regression-lifecycle distribution;
|
|
322
|
+
selecting a chart item filters
|
|
323
|
+
the issue table and selecting it again clears that filter;
|
|
324
|
+
- summary cards and partial-scan state;
|
|
325
|
+
- current and lifecycle tabs;
|
|
326
|
+
- severity, rule, inferred template, owner, and URL/text filters;
|
|
327
|
+
- evidence, before/after values, remediation, and fingerprint;
|
|
328
|
+
- engine and rule-set versions;
|
|
329
|
+
- client-side CSV export;
|
|
330
|
+
- print-friendly PDF layout;
|
|
331
|
+
- optional local agency name, logo, and primary color;
|
|
332
|
+
- clear clean-report and no-filter-match states.
|
|
333
|
+
|
|
334
|
+
Template grouping turns repeated findings such as `/products/red-shoe` and
|
|
335
|
+
`/products/blue-shirt` into `/products/:slug`. Numeric IDs, UUIDs, dates, and
|
|
336
|
+
hashes have stable placeholders. Grouping changes only presentation: rule IDs,
|
|
337
|
+
evidence, snapshots, and issue fingerprints remain unchanged.
|
|
338
|
+
|
|
339
|
+
Writes are atomic. Interactive scans refresh a partial report while results are
|
|
340
|
+
being checkpointed, so interruption does not discard already completed work.
|
|
341
|
+
|
|
342
|
+
## GitHub Action
|
|
343
|
+
|
|
344
|
+
The Action crawls entirely inside the GitHub runner. It produces exit status,
|
|
345
|
+
JSON summary, HTML report, job summary, and annotations for error-level
|
|
346
|
+
regressions.
|
|
302
347
|
|
|
303
348
|
```yaml
|
|
304
349
|
name: SEO regression check
|
|
305
|
-
|
|
306
|
-
on:
|
|
307
|
-
pull_request:
|
|
350
|
+
on: [pull_request]
|
|
308
351
|
|
|
309
352
|
jobs:
|
|
310
353
|
seo:
|
|
311
354
|
runs-on: ubuntu-latest
|
|
312
355
|
steps:
|
|
313
356
|
- uses: actions/checkout@v4
|
|
314
|
-
- uses:
|
|
357
|
+
- uses: MelnixDev/seo-crawl-audit@v0
|
|
358
|
+
id: seo
|
|
359
|
+
with:
|
|
360
|
+
url: https://preview.example.com/
|
|
361
|
+
baseline: .seo-audit.json
|
|
362
|
+
config: seo-audit.config.json
|
|
363
|
+
fail-on: error
|
|
364
|
+
report: seo-audit-report.html
|
|
365
|
+
- uses: actions/upload-artifact@v4
|
|
315
366
|
with:
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
367
|
+
name: seo-crawl-audit-report
|
|
368
|
+
path: |
|
|
369
|
+
${{ steps.seo.outputs.report }}
|
|
370
|
+
${{ steps.seo.outputs.summary }}
|
|
319
371
|
```
|
|
320
372
|
|
|
321
|
-
|
|
322
|
-
|
|
373
|
+
[Read all Action inputs and outputs](docs/github-action.md).
|
|
374
|
+
|
|
375
|
+
## Core API and repository structure
|
|
376
|
+
|
|
377
|
+
The npm workspace separates reusable concerns:
|
|
323
378
|
|
|
324
|
-
|
|
379
|
+
```text
|
|
380
|
+
packages/core @seo-crawl-audit/core — scan, audit, diff, snapshots, reports
|
|
381
|
+
packages/cli seo-crawl-audit — terminal UX and npm executable
|
|
382
|
+
packages/action @seo-crawl-audit/action — GitHub runner entry point
|
|
383
|
+
```
|
|
325
384
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
used for `robots.txt`, sitemap discovery, sitemap files, and HTML pages.
|
|
385
|
+
```ts
|
|
386
|
+
import { audit, planScan, scan } from "@seo-crawl-audit/core";
|
|
387
|
+
import { createFileCheckpointStore } from "@seo-crawl-audit/core/node";
|
|
330
388
|
|
|
331
|
-
|
|
389
|
+
const plan = await planScan({ url: "https://example.com/", maxPages: 100 });
|
|
390
|
+
const result = await scan(plan, {
|
|
391
|
+
signal: controller.signal,
|
|
392
|
+
checkpointStore: createFileCheckpointStore(".seo-audit.checkpoint.ndjson"),
|
|
393
|
+
onEvent(event) {
|
|
394
|
+
if (event.type === "progress") console.log(event.completed, event.total);
|
|
395
|
+
},
|
|
396
|
+
});
|
|
332
397
|
|
|
333
|
-
|
|
334
|
-
seo-audit https://example.com/ --delay 500
|
|
398
|
+
const issues = audit(result.snapshot);
|
|
335
399
|
```
|
|
336
400
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
401
|
+
[Read the typed public API guide](docs/public-api.md) and the
|
|
402
|
+
[architecture notes](docs/architecture.md).
|
|
403
|
+
|
|
404
|
+
## Responsible crawling and safe defaults
|
|
405
|
+
|
|
406
|
+
- delay: `100 ms` between request starts per origin;
|
|
407
|
+
- concurrency: `5`;
|
|
408
|
+
- timeout: `10 s`;
|
|
409
|
+
- `robots.txt` respected;
|
|
410
|
+
- same-origin page discovery;
|
|
411
|
+
- query strings excluded;
|
|
412
|
+
- HTML limited to `5 MiB` and robots to `512 KiB`;
|
|
413
|
+
- retries are bounded and use exponential backoff with jitter;
|
|
414
|
+
- `Retry-After` is honored up to 30 seconds;
|
|
415
|
+
- redirects are limited to 10.
|
|
416
|
+
|
|
417
|
+
Use a longer delay for a small site or a server you do not control:
|
|
340
418
|
|
|
341
419
|
```bash
|
|
342
|
-
seo-audit
|
|
420
|
+
seo-audit https://example.com/ --delay 500
|
|
343
421
|
```
|
|
344
422
|
|
|
345
|
-
|
|
346
|
-
so it is not a polite default for a public website. Increase concurrency or
|
|
347
|
-
reduce the delay only on sites you are allowed to test.
|
|
423
|
+
Use `--delay 0` only for local or explicitly controlled fixtures.
|
|
348
424
|
|
|
349
425
|
## Current scope
|
|
350
426
|
|
|
351
|
-
- server-rendered HTML
|
|
352
|
-
- same-origin
|
|
353
|
-
- sitemap and
|
|
354
|
-
-
|
|
355
|
-
-
|
|
356
|
-
-
|
|
357
|
-
- `robots.txt` responses are limited to 512 KiB;
|
|
358
|
-
- authenticated pages are not supported.
|
|
427
|
+
- server-rendered HTML; JavaScript rendering is not included;
|
|
428
|
+
- same-origin crawl discovery;
|
|
429
|
+
- sitemap and internal-link seeding;
|
|
430
|
+
- non-HTML responses are recorded but not parsed for page metadata;
|
|
431
|
+
- authenticated pages are not supported;
|
|
432
|
+
- results are normalized and ordered for reproducible output.
|
|
359
433
|
|
|
360
434
|
## Development
|
|
361
435
|
|
|
362
436
|
```bash
|
|
437
|
+
npm run build
|
|
363
438
|
npm test
|
|
364
439
|
npm run check
|
|
365
440
|
```
|
|
366
441
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
and
|
|
442
|
+
CI covers Node.js 20, 22, and 24. Tests use local HTTP fixtures for robots,
|
|
443
|
+
sitemaps, gzip, retries, redirects, cancellation, checkpoint resume, migration,
|
|
444
|
+
rules, lifecycle, HTML escaping, npm packaging, and the GitHub Action.
|
|
370
445
|
|
|
371
446
|
## License
|
|
372
447
|
|