minifetch-api 1.3.3 → 1.4.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 +43 -33
- package/dist/esm/client.js +8 -4
- package/dist/esm/utils/payment.js +20 -2
- package/dist/types/client.d.ts +8 -4
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -5,29 +5,33 @@
|
|
|
5
5
|
</a>
|
|
6
6
|
</div>
|
|
7
7
|
|
|
8
|
-
**[Minifetch](https://minifetch.com) is a hosted toolkit of
|
|
8
|
+
**[Minifetch](https://minifetch.com) is a hosted toolkit of web page extraction primitives.** Run them as a full technical SEO audit or call one at a time for a fraction of the price — and a fraction of the LLM tokens. No subscription.
|
|
9
9
|
|
|
10
10
|
- ✅ **Always pay-per-fetch at competitive prices.**
|
|
11
11
|
- ✅ [Sign up](https://minifetch.com/dashboard) for an account & get free starter credits. 🎉🎉
|
|
12
12
|
- ⛔ No charge for blocked pages (403 errors).
|
|
13
13
|
|
|
14
14
|
---
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
**👉 [Full API docs](https://minifetch.com/docs/api) | [LLMs.txt](https://minifetch.com/llms.txt) and [SKILL.md](https://minifetch.com/SKILL.md) for agents | Questions? Join our [Discord](https://discord.gg/EM6ET8Dshm)**
|
|
16
17
|
|
|
17
18
|
---
|
|
18
|
-
**Payments.** Two ways to pay:
|
|
19
|
-
1. Credit card + API key. Get started free - [visit our dashboard to Sign Up](https://minifetch.com/dashboard). Your account will be auto-loaded with 25 free technical SEO page audits. Top up with your credit card later.
|
|
20
|
-
2. USDC on Base or Solana. Just load your wallet with USDC and you're ready. No "gas token" (ETH or SOL) required.
|
|
21
19
|
|
|
22
20
|
## Prerequisites
|
|
23
21
|
|
|
24
22
|
- Node.js v18+ & NPM
|
|
25
23
|
- A valid API key from our [dashboard](https://minifetch.com/dashboard)
|
|
26
|
-
-
|
|
24
|
+
- ***Or*** an Ethereum or Solana private key for making USDC payments on Base or Solana networks.
|
|
27
25
|
|
|
28
|
-
|
|
26
|
+
**Payments.** Two ways to pay:
|
|
27
|
+
1. Credit card + API key. Get started free - [visit our dashboard to Sign Up](https://minifetch.com/dashboard). Create a Minifetch account and it will be auto-loaded with 25 free technical SEO page audits. Top up with your credit card later.
|
|
28
|
+
2. USDC on Base or Solana. Just load your wallet with USDC, you're ready. No "gas token" (ETH or SOL) required. You don't need a Minifetch account either, just load your wallet and go!
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
## Install
|
|
31
|
+
Add to your project:
|
|
32
|
+
```
|
|
33
|
+
npm install minifetch-api --save`
|
|
34
|
+
```
|
|
31
35
|
|
|
32
36
|
## Quick Start
|
|
33
37
|
|
|
@@ -66,9 +70,9 @@ try {
|
|
|
66
70
|
|
|
67
71
|
After the Quick Start, you have the following methods to use.
|
|
68
72
|
|
|
69
|
-
**Wrap** these methods in a **try/catch** just like in the Quick Start example above. **Code examples** can be also found in the [Github repository](https://github.com/Niche-Networks/minifetch-api/)
|
|
73
|
+
**Wrap** these methods in a **try/catch** just like in the Quick Start example above. **Code examples** can be also found in the [Github repository /example- directories](https://github.com/Niche-Networks/minifetch-api/).
|
|
70
74
|
|
|
71
|
-
The
|
|
75
|
+
The `checkAndExtract` methods check the target URL's `robots.txt` file to ensure its not blocked and tell us your preferred crawl delay (defaults to 1 second between requests to your domain). So fetching 10 URLs takes at least 10 seconds to complete by default. This is by design, so Minifetch never hammers your server or slows it down for your real users. If the URL is blocked, read [How To Unblock Minifetch](https://minifetch.com/tutorials/unblock-minifetch).
|
|
72
76
|
|
|
73
77
|
```js
|
|
74
78
|
await client.checkAndRunSeoPageAudit(url);
|
|
@@ -82,31 +86,31 @@ await client.checkAndRunSeoPageAudit(url);
|
|
|
82
86
|
|
|
83
87
|
await client.checkAndExtractUrlMetadata(url, options);
|
|
84
88
|
// Price: $0.002
|
|
85
|
-
// Extracts rich structured metadata from your URL:
|
|
86
|
-
// description, canonical, SEO-related meta tags, Open Graph and
|
|
87
|
-
// Twitter card tags, JSON-LD and more.
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
// and
|
|
91
|
-
// drop-in replacement for the npm `url-metadata` package.
|
|
89
|
+
// Extracts rich structured metadata from your URL: redirects, favicons,
|
|
90
|
+
// title, description, canonical, SEO-related meta tags, Open Graph and
|
|
91
|
+
// Twitter card tags, JSON-LD and more. Returns everything by default;
|
|
92
|
+
// narrow the response with the `fields` query param (pass atomic field
|
|
93
|
+
// names, ex: ?fields=title,description or the named groups: network,meta,
|
|
94
|
+
// og,twitter and/or meta:<name> for a specific page meta tag)
|
|
92
95
|
// Options:
|
|
93
|
-
// {
|
|
96
|
+
// { fields: ['canonical', 'og:url'] } - narrows to custom selected fields
|
|
97
|
+
// { omitEmpty: true } - defaults to false
|
|
94
98
|
// { includeResponseBody: true } - defaults to false
|
|
95
99
|
|
|
96
100
|
await client.checkAndExtractUrlLinks(url);
|
|
97
101
|
// Price: $0.002
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
102
|
+
// Extracts all links from your URL categorized by type (internal/
|
|
103
|
+
// external/ anchor). Detects image links, `rel` attributes (nofollow,
|
|
104
|
+
// sponsored, ugc, etc), `title` and `target`, plus image detection.
|
|
105
|
+
// Summary stats include the most-linked-to internal pages (with
|
|
106
|
+
// anchor text variants used for each) and top external domains by
|
|
107
|
+
// link count.
|
|
104
108
|
|
|
105
109
|
await client.checkAndExtractUrlPreview(url);
|
|
106
|
-
// Price: $0.
|
|
107
|
-
// For checking how your page unfurls when shared: Extracts
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
+
// Price: $0.002
|
|
111
|
+
// For checking how your web page unfurls when shared: Extracts all
|
|
112
|
+
// fields for the lightweight cards that represent your page on social
|
|
113
|
+
// platforms, chat apps and AI.
|
|
110
114
|
|
|
111
115
|
await client.checkAndExtractUrlContent(url, options);
|
|
112
116
|
// Price: $0.002
|
|
@@ -116,7 +120,7 @@ await client.checkAndExtractUrlContent(url, options);
|
|
|
116
120
|
// Options: { includeMediaUrls: true } - defaults to false.
|
|
117
121
|
|
|
118
122
|
// For max control, you can also use the following methods directly.
|
|
119
|
-
// Free
|
|
123
|
+
// Free: check if `minfetch` user agent can access target via robots.txt:
|
|
120
124
|
await client.preflightCheck(url);
|
|
121
125
|
// Paid methods:
|
|
122
126
|
await client.runSeoPageAudit(url);
|
|
@@ -125,10 +129,14 @@ await client.extractUrlLinks(url);
|
|
|
125
129
|
await client.extractUrlPreview(url);
|
|
126
130
|
await client.extractUrlContent(url, options); // same options as above
|
|
127
131
|
```
|
|
132
|
+
|
|
128
133
|
---
|
|
134
|
+
|
|
129
135
|
### Error Types
|
|
130
|
-
When you wrap the functions above in a try/catch, here are the errors you may encounter. You are never charged for URLs that are blocked or error.
|
|
136
|
+
When you wrap the functions above in a try/catch, here are some of the errors you may encounter. You are never charged for URLs that are blocked or error.
|
|
131
137
|
|
|
138
|
+
- **"InvalidURLError: Invalid url ${url}"**
|
|
139
|
+
- The URL is malformed in some way, correct it and try again.
|
|
132
140
|
- **"RobotsBlockedError: URL is blocked by robots.txt"**
|
|
133
141
|
- Minifetch is explicitly blocked by the website's `robots.txt`, cannot be fetched. If this is your site, read our tutorial [How To Unblock Minifetch](https://minifetch.com/tutorials/unblock-minifetch)
|
|
134
142
|
- **"Network Error: 402 Payment Required"**
|
|
@@ -139,23 +147,24 @@ When you wrap the functions above in a try/catch, here are the errors you may en
|
|
|
139
147
|
- URLs that pass their robots.txt check but are blocked anyway via 403 or other tactics may error like this. No charge.
|
|
140
148
|
- **"503 Service Temporarily Unavailable"**
|
|
141
149
|
- Likely encountering upstream timeout errors on the target URL.
|
|
142
|
-
|
|
143
|
-
- The URL is malformed in some way, correct it and try again.
|
|
150
|
+
|
|
144
151
|
---
|
|
152
|
+
|
|
145
153
|
### Service Limitations
|
|
146
154
|
Minifetch only extracts publicly available metadata and content from pages accessible without authentication and javascript execution.
|
|
147
155
|
|
|
148
156
|
What Minifetch does *NOT* do:
|
|
149
157
|
- Ignore robots.txt directives
|
|
150
|
-
- Access authenticated or logged-in content
|
|
151
158
|
- Create accounts or log into user sessions
|
|
152
159
|
- Perform transactional actions (checkout, bidding, purchasing, form submissions)
|
|
153
160
|
- Bypass paywalls or access restricted content
|
|
154
161
|
|
|
155
162
|
What Minifetch does NOT do *currently* but may offer in the future as an add-on:
|
|
156
163
|
- Javascript execution
|
|
164
|
+
- Access authenticated or logged-in content
|
|
157
165
|
|
|
158
166
|
---
|
|
167
|
+
|
|
159
168
|
### USDC Best Practices
|
|
160
169
|
- Uses the [x402 Protocol](https://www.x402.org/). No "gas token" (ETH or SOL) required, just load your wallet with USDC on Base or Solana network.
|
|
161
170
|
- LLMs & Agents should *never* have direct access to your private key. They *will* expose it!
|
|
@@ -164,6 +173,7 @@ What Minifetch does NOT do *currently* but may offer in the future as an add-on:
|
|
|
164
173
|
- Pass your private key into the Minifetch API Client with an [environment variable](https://developer.vonage.com/en/blog/how-to-use-environment-variables-in-javascript-with-dotenv).
|
|
165
174
|
|
|
166
175
|
---
|
|
176
|
+
|
|
167
177
|
**License**
|
|
168
178
|
|
|
169
179
|
MIT / Copyright (c) 2026 Lauren Garcia
|
package/dist/esm/client.js
CHANGED
|
@@ -67,7 +67,8 @@ export class MinifetchClient {
|
|
|
67
67
|
*
|
|
68
68
|
* @param url
|
|
69
69
|
* @param options
|
|
70
|
-
* @param options.
|
|
70
|
+
* @param options.fields
|
|
71
|
+
* @param options.omitEmpty
|
|
71
72
|
* @param options.includeResponseBody
|
|
72
73
|
* @throws {InvalidUrlError} if URL is invalid
|
|
73
74
|
* @throws {ExtractionFailedError} various reasons, check README
|
|
@@ -78,8 +79,10 @@ export class MinifetchClient {
|
|
|
78
79
|
try {
|
|
79
80
|
const normalizedUrl = validateAndNormalizeUrl(url);
|
|
80
81
|
const params = new URLSearchParams({ url: normalizedUrl });
|
|
81
|
-
if (options?.
|
|
82
|
-
params.set("
|
|
82
|
+
if (options?.fields?.length)
|
|
83
|
+
params.set("fields", options.fields.join(","));
|
|
84
|
+
if (options?.omitEmpty)
|
|
85
|
+
params.set("omitEmpty", "true");
|
|
83
86
|
if (options?.includeResponseBody)
|
|
84
87
|
params.set("includeResponseBody", "true");
|
|
85
88
|
const requestUrl = `${this.baseUrl}${this._paidPath("/extract/url-metadata")}?${params.toString()}`;
|
|
@@ -167,7 +170,8 @@ export class MinifetchClient {
|
|
|
167
170
|
*
|
|
168
171
|
* @param url
|
|
169
172
|
* @param options
|
|
170
|
-
* @param options.
|
|
173
|
+
* @param options.fields
|
|
174
|
+
* @param options.omitEmpty
|
|
171
175
|
* @param options.includeResponseBody
|
|
172
176
|
*/
|
|
173
177
|
async checkAndExtractUrlMetadata(url, options) {
|
|
@@ -42,7 +42,8 @@ export async function handlePayment(url, config) {
|
|
|
42
42
|
const fetchWithPayment = wrapFetchWithPayment(fetch, _x402Client);
|
|
43
43
|
const response = await fetchWithPayment(url, { method: "GET" });
|
|
44
44
|
if (!response.ok) {
|
|
45
|
-
|
|
45
|
+
const serverMessage = await readServerErrorMessage(response);
|
|
46
|
+
throw new NetworkError(`Request failed: ${response.status} ${response.statusText}${serverMessage ? ` — ${serverMessage}` : ""}`);
|
|
46
47
|
}
|
|
47
48
|
const httpClient = new x402HTTPClient(_x402Client);
|
|
48
49
|
const paymentResponse = httpClient.getPaymentSettleResponse(name => response.headers.get(name));
|
|
@@ -79,7 +80,8 @@ export async function handleApiKeyRequest(url, config) {
|
|
|
79
80
|
},
|
|
80
81
|
});
|
|
81
82
|
if (!response.ok) {
|
|
82
|
-
|
|
83
|
+
const serverMessage = await readServerErrorMessage(response);
|
|
84
|
+
throw new NetworkError(`Request failed: ${response.status} ${response.statusText}${serverMessage ? ` — ${serverMessage}` : ""}`);
|
|
83
85
|
}
|
|
84
86
|
return { response };
|
|
85
87
|
}
|
|
@@ -101,3 +103,19 @@ function getExplorerLink(config, txHash) {
|
|
|
101
103
|
return "";
|
|
102
104
|
}
|
|
103
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Best-effort read of the rich server error message from a non-ok response.
|
|
108
|
+
* Minifetch error bodies carry it at results[0].error.message.
|
|
109
|
+
*
|
|
110
|
+
* @param response - non-ok Response (body is consumed)
|
|
111
|
+
*/
|
|
112
|
+
async function readServerErrorMessage(response) {
|
|
113
|
+
try {
|
|
114
|
+
const body = (await response.json());
|
|
115
|
+
// TODO: revisit this approach when we scale up to multiple results per request
|
|
116
|
+
return body?.results?.[0]?.error?.message;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
}
|
package/dist/types/client.d.ts
CHANGED
|
@@ -36,7 +36,8 @@ export declare class MinifetchClient {
|
|
|
36
36
|
*
|
|
37
37
|
* @param url
|
|
38
38
|
* @param options
|
|
39
|
-
* @param options.
|
|
39
|
+
* @param options.fields
|
|
40
|
+
* @param options.omitEmpty
|
|
40
41
|
* @param options.includeResponseBody
|
|
41
42
|
* @throws {InvalidUrlError} if URL is invalid
|
|
42
43
|
* @throws {ExtractionFailedError} various reasons, check README
|
|
@@ -44,7 +45,8 @@ export declare class MinifetchClient {
|
|
|
44
45
|
* @throws {NetworkError} various reasons, check README
|
|
45
46
|
*/
|
|
46
47
|
extractUrlMetadata(url: string, options?: {
|
|
47
|
-
|
|
48
|
+
fields?: string[];
|
|
49
|
+
omitEmpty?: boolean;
|
|
48
50
|
includeResponseBody?: boolean;
|
|
49
51
|
}): Promise<PaidEndpointResponse>;
|
|
50
52
|
/**
|
|
@@ -94,11 +96,13 @@ export declare class MinifetchClient {
|
|
|
94
96
|
*
|
|
95
97
|
* @param url
|
|
96
98
|
* @param options
|
|
97
|
-
* @param options.
|
|
99
|
+
* @param options.fields
|
|
100
|
+
* @param options.omitEmpty
|
|
98
101
|
* @param options.includeResponseBody
|
|
99
102
|
*/
|
|
100
103
|
checkAndExtractUrlMetadata(url: string, options?: {
|
|
101
|
-
|
|
104
|
+
fields?: string[];
|
|
105
|
+
omitEmpty?: boolean;
|
|
102
106
|
includeResponseBody?: boolean;
|
|
103
107
|
}): Promise<PaidEndpointResponse>;
|
|
104
108
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "minifetch-api",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Minifetch.com API Client. Pay-per-URL SEO audits. Composable toolkit for AI agents and automation pipelines.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/esm/index.js",
|
|
@@ -21,14 +21,18 @@
|
|
|
21
21
|
"SEO page audit",
|
|
22
22
|
"SEO research",
|
|
23
23
|
"SEO toolkit",
|
|
24
|
+
"SEO skill",
|
|
24
25
|
"technical SEO",
|
|
25
|
-
"pay-per-fetch
|
|
26
|
-
"pay-per-url
|
|
26
|
+
"pay-per-fetch",
|
|
27
|
+
"pay-per-url",
|
|
27
28
|
"GEO",
|
|
29
|
+
"Generative Engine Optimization",
|
|
28
30
|
"AEO",
|
|
29
|
-
"
|
|
31
|
+
"Answer Engine Optimization",
|
|
32
|
+
"hosted extraction",
|
|
30
33
|
"content extraction",
|
|
31
34
|
"content indexing",
|
|
35
|
+
"extract",
|
|
32
36
|
"html",
|
|
33
37
|
"html parser",
|
|
34
38
|
"json-ld",
|
|
@@ -47,6 +51,7 @@
|
|
|
47
51
|
"monitoring",
|
|
48
52
|
"LLM",
|
|
49
53
|
"previews",
|
|
54
|
+
"social cards",
|
|
50
55
|
"twitter cards",
|
|
51
56
|
"site monitoring",
|
|
52
57
|
"x402",
|