Key takeaways
fetch()is the browser’s built-in way to call APIs and load data without reloading the page.- Always check
response.ok, handle errors and show loading states. - Never put secret API keys in browser code — call third-party APIs from your server instead.
Live search, chat assistants, “load more” buttons, form submissions without page reloads, dashboards that refresh — all use the Fetch API. The chatbot on this site sends your message to a WordPress REST endpoint with fetch, and the server talks to the AI provider so no key is ever exposed. Here’s how it works.
A basic GET request#
async function loadPosts() {
const res = await fetch('/wp-json/wp/v2/posts?per_page=5');
if (!res.ok) throw new Error('HTTP ' + res.status);
const posts = await res.json();
return posts.map(p => p.title.rendered);
}
fetch returns a Promise. The response doesn’t throw on 404 or 500 errors — you must check res.ok (true for status 200–299).
Sending data with POST#
const res = await fetch('/wp-json/ikp/v1/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ messages: [{ role: 'user', content: 'What is TTFB?' }] })
});
const data = await res.json();
For HTML forms, send new FormData(formElement) as the body and skip the Content-Type header — the browser sets it.
Robust error handling and timeouts#
async function getJSON(url, ms = 10000) {
const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), ms);
try {
const res = await fetch(url, { signal: ctrl.signal });
if (!res.ok) throw new Error('Server error ' + res.status);
return await res.json();
} finally {
clearTimeout(t);
}
}
- Show a loading indicator and disable the button while waiting.
- Show a friendly message on failure, with a retry option.
- Cancel outdated requests (e.g. previous search keystrokes) with
AbortController. - Debounce input-driven requests (wait ~200–300 ms after typing stops).
Need a hand with this?
Get a quick, honest review of your website’s SEO.
Security essentials#
| Risk | Solution |
|---|---|
| Exposed API keys | Proxy calls through your server (WordPress REST route, serverless function) |
| Cross-site request forgery | Nonces/CSRF tokens for actions that change data; same-origin checks |
| Abuse and spam | Rate limiting per IP or user on the server |
| XSS when displaying results | Insert with textContent or escape HTML |
| CORS errors | The API must allow your origin; you can’t fix CORS from the browser side |
Caching and performance#
- Let the server set
Cache-Controlheaders for data that rarely changes (this site’s search index is cached for 15 minutes). - Load data once and reuse it in memory (the quick search fetches its index only on first focus).
- Use
cache: 'no-store'for one-time tokens like captchas. - Paginate large datasets rather than loading thousands of records.
WordPress REST API examples#
/wp-json/wp/v2/posts?search=redirect // search posts
/wp-json/wp/v2/categories // list categories
/wp-json/wp/v2/pages?slug=contact // get a page by slug
Custom endpoints are registered in PHP with register_rest_route(), with a permission_callback that controls who can call them. More on APIs: REST APIs explained.
Fetch API FAQ#
Fetch or Axios?#
Fetch is built in and enough for most projects. Axios adds conveniences like interceptors and automatic JSON handling.
Why do I get a CORS error?#
The API server doesn’t allow requests from your domain. Configure CORS on the server, or call the API from your own backend.
Is content loaded with fetch indexed by Google?#
It can be, after rendering, but it’s less reliable. Keep SEO-important content in the initial HTML.