minifetch-api 1.3.4 → 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 CHANGED
@@ -5,19 +5,17 @@
5
5
  </a>
6
6
  </div>
7
7
 
8
- **[Minifetch](https://minifetch.com) is a hosted toolkit of extraction primitives for SEO/ GEO/ AEO.** Run them as a full technical audit or call one at a time for a fraction of the price — and a fraction of the LLM tokens. No subscription.
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). Create a Minifetch account and it 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, you're ready. No "gas token" (ETH or SOL) required. You don't need a Minifetch account either, just load your wallet and go!
21
19
 
22
20
  ## Prerequisites
23
21
 
@@ -25,9 +23,15 @@
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
- ## Install
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
- `npm install minifetch-api --save`
30
+ ## Install
31
+ Add to your project:
32
+ ```
33
+ npm install minifetch-api --save`
34
+ ```
31
35
 
32
36
  ## Quick Start
33
37
 
@@ -66,7 +70,7 @@ 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/) /example- directories.
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
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
 
@@ -82,15 +86,15 @@ 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: favicons, title,
86
- // description, canonical, SEO-related meta tags, Open Graph and
87
- // Twitter card tags, JSON-LD and more.
88
- // Set verbosity option to full for more fields: redirect chain,
89
- // relevant response headers, performance metrics, headings, images
90
- // and every meta tag found on the page; verbosity "full" is the
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
- // { verbosity: "full" } - defaults to "standard"
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);
@@ -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,9 +147,9 @@ 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
- - **"InvalidURLError: Invalid url ${url}"**
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
 
@@ -156,6 +164,7 @@ What Minifetch does NOT do *currently* but may offer in the future as an add-on:
156
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
@@ -67,7 +67,8 @@ export class MinifetchClient {
67
67
  *
68
68
  * @param url
69
69
  * @param options
70
- * @param options.verbosity - "standard" (default) or "full"
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?.verbosity)
82
- params.set("verbosity", options.verbosity);
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.verbosity - "standard" (default) or "full"
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
- throw new NetworkError(`Request failed: ${response.status} ${response.statusText}`);
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
- throw new NetworkError(`Request failed: ${response.status} ${response.statusText}`);
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
+ }
@@ -36,7 +36,8 @@ export declare class MinifetchClient {
36
36
  *
37
37
  * @param url
38
38
  * @param options
39
- * @param options.verbosity - "standard" (default) or "full"
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
- verbosity?: "standard" | "full";
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.verbosity - "standard" (default) or "full"
99
+ * @param options.fields
100
+ * @param options.omitEmpty
98
101
  * @param options.includeResponseBody
99
102
  */
100
103
  checkAndExtractUrlMetadata(url: string, options?: {
101
- verbosity?: "standard" | "full";
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.4",
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",