npm i grab-url # ~5 kB gzipped, zero dependencies, no install scriptsGRAB is the FBEST Request Manager: Functionally Brilliant, Elegantly Simple Tool β One Function, no dependencies, minimalist syntax, more features than alternatives
Send anything, get back parsed data β no boilerplate per content type.
- Auto-JSON Convert: Pass parameters and get response or error in JSON, handling other data types as is.
- Auto-Unzip: Automatically extracts ZIP responses into
{ data: { filename: content } }using archiver-web. Setunzip: falseto disable. Import fromgrab-url/fullβ see Slim by default. - DOM Parsing: Automatically parses HTML responses. Pass
parseDOM: "selector"for CSS selector extraction orparseDOM: falseto disable. Uses linkedom. Import fromgrab-url/fullβ see Slim by default. - Request Stategies: π― Examples show common stategies like debounce, repeat, proxy, unit tests, interceptors, file upload, etc
- Runtime Support: π‘οΈ Runtime support & behavior contract lists what each runtime (browsers, Node, Bun, Deno, Workers, SSR) needs, what CI verifies there, the
GrabErrorcodes and plugin lifecycle, and the known quirks
Keep flaky networks and click-happy users from cascading into your API.
- Cancel Duplicates: Prevent this request if one is ongoing to same path & params, or cancel the ongoing request.
- Timeout & Retry: Customizable request timeout, default 30s, and auto-retry on error
- Regrab On Error: Regrab on timeout error, or on window refocus, or on network change, or on stale data.
- Rate Limiting: Built-in rate limiting to prevent multi-click cascading responses, require to wait seconds between requests.
- Repeat: Repeat request this many times, or repeat every X seconds to poll for updates.
Fewer round trips, and loading state your components can bind to directly.
- isLoading Status: Sets
.isLoading=trueon the pre-initialized response object so you can show a "Loading..." in any framework - Frontend Cache: Set cache headers and retrieve from frontend memory for repeat requests to static data.
- Pagination Infinite Scroll: Built-in pagination for infinite scroll to auto-load and merge next result page, with scroll position recovery.
- Loading Icons: Import from
grab-url/iconsto get enhanced animated loading icons, including the quantum sphere β an interactive 3D orbital loader for React and Svelte that re-rolls its own colors and collapses each ring you hover:import QuantumOrbital from 'grab-url/icons/quantum-sphere'.
See every request, fake the ones you don't have yet, and assert on the rest.
- Mock Server Support: Configure
window.grab.mockfor development and testing environments - DevTools:
Ctrl+Alt+Ioverlays webpage with devtools showing all requests and responses, timing, and JSON structure. - Debug Logging: Adds global
log()and prints colored JSON structure, response, timing for requests in test. - Request History: Stores all request and response data in global
grab.logobject
Drop it into any stack, any runtime, or generate a whole client from a spec.
- Agent Skill Install the skill into any agent (Claude, Cursor, Gemini, Codex, Antigravity, etc.) with one command:
npx skills add vtempest/GRAB-URL@use-grab-request. Or copy SKILL.md into~/.claude/skills/use-grab-request/SKILL.md. - Globals: Adds to window in browser or global in Node.js so you only import once:
grab(),log(),grab.log,grab.mock,grab.defaults - Base URL Based on Environment: Configure
grab.defaults.baseURLonce at the top, overide withSERVER_API_URLin.env. - Framework Agnostic: Alternatives like TanStack work only in component initialization and depend on React & others.
- OpenAPI SDKs: Generate a typed client from any OpenAPI spec with Hey API and have it send requests with grab instead of axios:
npx api2client ./openapi.yaml ./src/client. Every endpoint gets caching, retries, rate limiting, dedupe and mocks.
import grab from "grab-url" gives you the slim build: about 5 kB gzipped, zero
dependencies, nothing lazily reachable that you did not ask for. That is every feature
above except the two that need a heavy library β ZIP extraction and HTML/DOM parsing.
Those two live one subpath away:
import grab from "grab-url"; // default β ~5 kB gzipped
import grab from "grab-url/full"; // + `unzip` and `parseDOM`grab-url/full adds linkedom (~174 kB) and the archive extractor, both behind lazy
imports, so they download only when a response actually needs one of them. grab-url/slim
still resolves, as an alias of the default β it is the identical module, so a stub on
grab.mock registered through either specifier is visible to the other.
The CLI is its own package, grab-url-cli.
Installing the library runs no install script and pulls nothing down.
| Package | Gives you | Pick it when |
|---|---|---|
grab-url |
grab(), log(), plus grab-url/animations (~25 tree-shakable SVG spinners) and grab-url/icons/quantum-sphere (a 3D React/Svelte loader) |
You want the request client and the loading UI |
grab-api.js |
grab() and log() β the same core, same /full subpath, nothing else |
You only want the request client |
grab-url-cli |
the grab-url / grab / g commands |
You want the terminal downloader |
grab-url and grab-api.js are built from the same source, so install one, not both β
a project holding both ends up with two grab() modules, two grab.mock registries and
two caches, and a stub registered on one is invisible to the other.
CLI File Downloader β npm i -g grab-url-cli, or just npx grab-url (no install)
npx grab-url https://releases.ubuntu.com/24.04.2/ubuntu-24.04.2-live-server-amd64.iso
# 700+ media sites are detected by domain and pulled with yt-dlp, which
# installing grab-url-cli fetches for you
npx grab-url "https://www.youtube.com/watch?v=VIDEO_ID"
npx grab-url https://soundcloud.com/artist/track -a mp3
# SFTP, torrents and magnet links (needs aria2c installed)
npx grab-url sftp://user@host/srv/backup.tar.gz --password hunter2
npx grab-url "magnet:?xt=urn:btih:HASH" -d ./downloads
# Archive a page into ./<Page Title>/ - article, cite, transcript and any video
# (needs `npm i -g extract-webpage`; the video step needs yt-dlp)
npx grab-url https://example.com/article --page
# Detach and keep going in the background; Ctrl+C on any transfer offers the same
npx grab-url https://example.com/big.iso --background
npx grab-url --jobsimport grab from 'grab-url';
let res = $state({}) as {
results: Array<{title:string}>,
isLoading: boolean,
error: string,
};
await grab('search', {
response: res,
query: "search words",
post: true
})
grab('user').then(log)
// Auto-extract ZIP files
const zipData = await grab('https://example.com/archive.zip', {
unzip: true
})
// { data: { "file1.txt": "content...", "file2.js": "..." } }
// Parse HTML and extract elements
const title = await grab('https://example.com', {
parseDOM: 'h1'
})
// { data: "Page Title" }
//in svelte component
{#if res.results}
{res.results}
{:else if res.isLoading}
...
{:else if res.error}
{res.error}
{/if}
//Setup Mock testing server, response is object or function
window.grab.mock["search"] = {
response: (params) => {
return { results: [{title:`Result about ${params.query}`}] };
},
method: "POST"
};
//set defaults for all requests
grab("", {
setDefaults: true,
baseURL: "http://localhost:8080",
timeout: 30,
debug: true,
rateLimit: 1,
cache: true,
cancelOngoingIfNew: true,
});
grab.defaults.baseURL = "http://localhost:8080/api/";Animated SVG Loading Icons with Customizable Colors
Quantum Sphere Loader β live demo
Screencast_20251208_051849.mp4
Set Types for Tooltips on Request & Response
Debug Colorized log(JSON)
| Feature | GRAB | Axios | TanStack Query | SWR | Alova | SuperAgent | Apisauce | Ky |
|---|---|---|---|---|---|---|---|---|
| Size | β 4KB | β 13KB | β 39KB | β 4.2KB | β 4KB | β 19KB | β 15KB (with axios) | β 4KB |
| Zero Dependencies | β Yes | β No | β No | β No | β Yes | β No | β Needs Axios | β Yes |
| isLoading State Handling | β Auto-managed | β Manual | β Yes | β Yes | β Yes | β Manual | β Manual | β Manual |
| Auto JSON Handling | β Automatic | β Configurable | β Manual | β Manual | β Automatic | β Automatic | β Automatic | β Automatic |
| Request Deduplication | β Built-in | β No | β Yes | β Yes | β Yes | β No | β No | β No |
| Caching | β Multi-level | β No | β Advanced | β Advanced | β Multi-level | β No | β No | β No |
| Mock Testing | β Easy setup | β Needs MSW/etc | β Needs MSW/etc | β Needs MSW/etc | β Needs separate lib | β Needs separate lib | β Needs MSW/etc | |
| Rate Limiting | β Built-in | β Manual | β Manual | β Manual | β Manual | β Manual | β Manual | |
| Automatic Retry | β Configurable | β Built-in | β Built-in | β Built-in | β Built-in | β Manual | β Built-in | |
| Request Cancellation | β Auto + manual | β Manual | β Automatic | β Automatic | β Manual | β Manual | β Manual | β Manual |
| Pagination Support | β Infinite scroll | β Manual | β Advanced | β Built-in | β Manual | β Manual | β Manual | |
| Interceptors | β Advanced | β Advanced | β Advanced | β Plugins | β Transforms | β Hooks system | ||
| Debug Logging | β Colored output | β DevTools | β DevTools | |||||
| Request History | β Built-in | β Manual | β DevTools | β DevTools | β Manual | β Manual | β Manual | β Manual |
| Easy Syntax | β Minimal | β High | β High | β Low | β Minimal |
Stop trying to make fetch happen! *
Why fetch things when you can just GRAB?
Debugging requests is a bitch. Make the switch!
π Star this repo so it will grow and get updates!



