GuidesFUN APIS
Free quotes API for JavaScript
DummyJSON is the easiest free quotes API for browser JavaScript: 1,454 quotes, no key and CORS headers on every response. ZenQuotes has 3,237 quotes and needs no key either, but it sends no Access-Control-Allow-Origin header unless you pay, so prefix it with the free proxy https://proxy.cors.dev/, no signup. We tested 10 quotes APIs on 28 October 2026: 4 send CORS headers, and api.quotable.io, the one most tutorials use, no longer resolves. Token-protected endpoints such as FavQs need cors.dev Pro, $5 a month for 500,000 requests with a 7-day trial of 1,000 requests and no card.
Which quotes API works from the browser
We called 10 quotes APIs on 28 October 2026 with an Origin header of https://example.com, as a browser does, then through https://proxy.cors.dev/. Four send CORS headers that let fetch() read the response from any site; api.quotable.io and Forismatic were unreachable.
| API | Free tier | Key | Browser CORS | Through cors.dev |
|---|---|---|---|---|
| DummyJSON | 1,454 quotes, no signup | None | Yes, echoes the origin | Not needed |
| ZenQuotes | 5 requests per 30 seconds per IP, attribution link | None, paid key in the URL path | No, only with a paid key | Works on the free proxy |
| FavQs | Random quote at /api/qotd, 30 requests per 20 seconds | None for /api/qotd, token header for the rest | No | qotd on the free proxy, token needs cors.dev Pro |
| API Ninjas | 3,000 calls a month, 100 an hour, non-commercial | X-Api-Key header | Yes, any origin | Not needed, free proxy refuses the key |
| Quotable community mirror | 2,107 quotes, no stated limit | None | Yes, any origin | Not needed |
| Quotable (api.quotable.io) | Offline, the domain no longer resolves | None | Unreachable | 502 upstream_unreachable |
| They Said So | No free calls in our test, Premium is $9.99 a month | X-TheySaidSo-Api-Secret header | No header on 401 or preflight | Key header needs cors.dev Pro |
| kanye.rest | One Kanye West quote per call | None | Yes, any origin | Not needed |
| type.fit | 5 quotes left | None | No | Works, still 5 quotes |
| Forismatic | Down, Cloudflare 522 | None | Unreachable | 522 |
ZenQuotes sends no CORS header without a key
ZenQuotes has 3,237 quotes from 256 authors and needs no key. /api/random returns one quote, /api/today the quote of the day (it changes at midnight US Central time) and /api/quotes 50 random quotes in one 13,140-byte call. Each response is a JSON array of objects with q (quote), a (author) and h (ready-made HTML).
Without a key ZenQuotes sends no Access-Control-Allow-Origin header, so fetch() from a page fails with a missing Access-Control-Allow-Origin error. A key, from $7.99 a month at my.zenquotes.io, turns the header on, but it sits in the URL path (/api/today/YOUR_KEY) where every visitor can read it.
Free use allows 5 requests per 30 seconds per IP and requires a visible link to https://zenquotes.io/. Our 6th direct request in a row answered 429 with a body shaped like a quote: q was "Too many requests. Obtain an auth key for unlimited access." Check response.ok, or your widget shows the error as a quote.
Through the free proxy all three endpoints answered 200 with Access-Control-Allow-Origin set to the calling origin. ZenQuotes then counts the proxy's address, which other cors.dev users share, so cache the quote and keep a second provider. This snippet fetches /api/today through the proxy, falls back to DummyJSON on any error and keeps one quote per day in localStorage:
const PROXY = 'https://proxy.cors.dev/';
async function fetchQuote() {
try {
const response = await fetch(PROXY + 'https://zenquotes.io/api/today');
if (!response.ok) throw new Error(`ZenQuotes answered ${response.status}`);
const [{ q, a }] = await response.json();
return { text: q, author: a, credit: 'https://zenquotes.io/' };
} catch (error) {
console.warn(`${error.message}, using DummyJSON instead`);
const response = await fetch('https://dummyjson.com/quotes/random');
if (!response.ok) throw new Error(`DummyJSON answered ${response.status}`);
const { quote, author } = await response.json();
return { text: quote, author, credit: 'https://dummyjson.com/' };
}
}
// Keep one quote per day so repeat visits cost no requests
const today = new Date().toISOString().slice(0, 10);
const cached = JSON.parse(localStorage.getItem('quote-of-the-day') ?? 'null');
const quote = cached?.day === today ? cached.quote : await fetchQuote();
localStorage.setItem('quote-of-the-day', JSON.stringify({ day: today, quote }));
console.log(`"${quote.text}" (${quote.author}), quotes by ${quote.credit}`);Quote APIs that work with plain fetch()
These need no key and no proxy:
- DummyJSON: 1,454 quotes from 89 authors, with the calling origin echoed in
Access-Control-Allow-Origin./quotes/randomreturns{ id, quote, author },/quotes/random/10returns 10 and/quotes?limit=0returns all of them;skipandselectpage and trim the list. - Quotable community mirror:
api.quotable.kurokeita.dev, one developer's MIT-licensed rebuild of Quotable, has 2,107 quotes and sendsAccess-Control-Allow-Origin: *./api/quotes/randomreturns{ quote: { content, author: { name } } }rather than Quotable's top-level fields, so old code needs changes. Fine for a demo, not something to depend on. - kanye.rest:
api.kanye.restsendsAccess-Control-Allow-Origin: *and returns{ "quote": "..." }with one Kanye West quote.
What happened to Quotable
Quotable (api.quotable.io) is the API most older tutorials use. On 28 October 2026 its domain no longer resolved in DNS, and through cors.dev it answered 502 with upstream_unreachable. Its certificate expired on 10 September 2024 and "API is down" issues on its GitHub repository ran through September 2026, so replace it rather than proxy it.
Two other tutorial favourites fail too: type.fit/api/quotes answered 200 with only 5 quotes (443 bytes) and no CORS header, and Forismatic answered a Cloudflare 522 both directly and through the proxy after about 19 seconds.
API Ninjas, FavQs and They Said So keys
API Ninjas takes its key in the X-Api-Key header on /v2/quoteoftheday, /v2/randomquotes and /v2/quotes. It sends Access-Control-Allow-Origin: * and its preflight allows X-Api-Key, so fetch() works directly, with the key visible in DevTools. The free plan gives 3,000 calls a month and 100 an hour for evaluation and demo use, with attribution. No proxy needed; the free one refuses X-Api-Key anyway.
FavQs serves /api/qotd without a token but sends no CORS header, so call it through the free proxy (it answered 200). It returned a different quote on each of 4 calls in a row, so cache it if you want one per day. Every other endpoint, such as /api/quotes/?filter=funny&type=tag, needs Authorization: Token token="YOUR_APP_TOKEN". FavQs answered the OPTIONS preflight with 404, so the browser blocks these calls even with a valid token, and the free proxy refuses Authorization with 400 header_not_allowed.
cors.dev Pro forwards Authorization and custom headers:
- Sign up
Use cors.dev/signup with Google; the 7-day trial includes 1,000 requests and needs no card.
- Create a Connection
Enter your exact page origin and the target host
favqs.com. - Send both headers
Put the Connection's publishable key in
X-Cors-Keyand your FavQs token inAuthorization.
const PROXY = 'https://proxy.cors.dev/';
const favqsToken = 'YOUR_FAVQS_APP_TOKEN';
const url = 'https://favqs.com/api/quotes/?' + new URLSearchParams({ filter: 'programming', type: 'tag' });
const response = await fetch(PROXY + url, {
headers: {
'X-Cors-Key': 'YOUR_CONNECTION_KEY',
Authorization: `Token token="${favqsToken}"`,
},
});
const proxyError = response.headers.get('X-Cors-Error');
if (proxyError) throw new Error(`cors.dev: ${proxyError}`);
if (!response.ok) throw new Error(`FavQs answered ${response.status}`);
// FavQs reports validation errors with HTTP 200 and an error_code
const data = await response.json();
if (data.error_code) throw new Error(`FavQs error ${data.error_code}: ${data.message}`);
for (const quote of data.quotes.slice(0, 5)) {
console.log(`${quote.body} (${quote.author})`);
}FavQs reports validation errors as HTTP 200 with an error_code field, which the snippet checks. cors.dev does not hide the token: anyone can read it in DevTools, so cors.dev Pro fits internal tools and prototypes, and a public site should call FavQs from a backend.
They Said So (quotes.rest) has over a million quotes; Premium costs $9.99 a month for 2,500 calls a day. Its docs promise public Quote of the Day calls and Access-Control-Allow-Origin: * on every response, but without a valid key every endpoint we tried, including /qod?category=inspire, answered 401 "Not authenticated" with no CORS header, and so did the preflight. The key goes in X-TheySaidSo-Api-Secret, which the free proxy refuses because the name contains "secret"; cors.dev Pro forwards it.
Limits to plan for
- Vendors: ZenQuotes allows 5 requests per 30 seconds per IP without a key, FavQs 30 per 20 seconds per session and API Ninjas 100 an hour.
- cors.dev free: No signup,
GETandHEADonly, about 600 requests a minute per IP, responses up to 6 MiB and a 30-second upstream deadline. Header names containingtoken,apikey,api-key,api_key,secretorpassword, or ending in-key, get400 header_not_allowed; keys in the URL are forwarded as-is. - cors.dev Pro: $5 a month for 500,000 requests, 3,000 requests a minute per account and 100 in flight, with the same 6 MiB and 30-second caps.
Good questions.
Which free quotes APIs need no API key at all?
DummyJSON, the Quotable community mirror at api.quotable.kurokeita.dev and kanye.rest need no key and send CORS headers, so fetch() works directly. ZenQuotes and the FavQs /api/qotd endpoint need no key either but send no CORS header, so call them through https://proxy.cors.dev/.
Why does fetch() to ZenQuotes fail with a CORS error?
ZenQuotes sends no Access-Control-Allow-Origin header unless you use a paid key, from $7.99 a month, or a registered IP. Without it the browser blocks your page from reading the response. Prefixing the URL with https://proxy.cors.dev/ adds the header for free, and the limit of 5 requests per 30 seconds then applies to the proxy's address.
Is api.quotable.io down, and what replaces it?
Yes. On 28 October 2026 the domain no longer resolved, and its certificate had expired on 10 September 2024. DummyJSON's 1,454 quotes are the closest keyless, CORS-ready replacement; the mirror at api.quotable.kurokeita.dev keeps Quotable-style paths with a nested response.
Can I call the API Ninjas quotes API from browser JavaScript?
Yes. It sends Access-Control-Allow-Origin: * and its preflight allows the X-Api-Key header, so no proxy is needed. Every visitor can read the key in DevTools, and the free plan allows 3,000 calls a month for non-commercial use with attribution.
Does cors.dev hide my quotes API key?
No. A key in the URL or in a header is visible in the browser's network tab, and the Connection key in X-Cors-Key is publishable by design. Use cors.dev Pro for internal tools and prototypes, and call keyed APIs from your own backend on a public site.