Fetch Remote Data
Goal: pull third-party API data with LFHttp and render it — a live USD exchange-rate panel.
main.js
js
// ==UserScript==
// @name USD Rate Panel
// @description Show live USD exchange rates on the page
// @match https://example.com/*
// @require dom
// @require http
// ==/UserScript==
LFDOM.ready(async () => {
const panel = LFDOM.createFloatingRoot({ id: "usd-rates" });
panel.innerHTML = "<div style='padding:10px 14px'>Loading...</div>";
try {
const data = await LFHttp.json("https://open.er-api.com/v6/latest/USD");
panel.firstElementChild.textContent = `1 USD = ${data.rates.CNY} CNY`;
} catch (error) {
panel.firstElementChild.textContent = `Failed to load: ${error.message}`;
}
});Why not plain fetch?
In-page fetch is constrained by the host site's CSP and CORS. LFHttp routes through the extension background, bypassing those limits with clear guardrails:
- Rejects the local PluginX client port (
41720on any loopback form; useLFHttp.client),chrome-extension://,file://, and non-http(s) targets (the address after a redirect is checked too) - Attaches the target domain's existing browser cookies by default (pass
credentials: 'omit'to disable); browser-reserved headers such asCookie/Referer/User-Agentcan be set explicitly viaheadersand are written on the wire (aCookieheader replaces the browser's own cookies) - Object bodies are
JSON.stringify'd, butContent-Typeis not set for you — addheaders: { "content-type": "application/json" }when sending JSON - Supports
stream()for streaming responses andwebsocket()for long-lived connections - For a timeout or mid-flight cancel, pass
signal(e.g.signal: AbortSignal.timeout(10000)): the request is really cancelled and rejects with anAbortErrorwhosecodeis'ABORTED'(the browser throttlesAbortSignal.timeoutin hidden tabs, so it may fire seconds late)
Note
Failed requests throw: non-2xx throws HTTPError, network faults such as DNS failure or a refused connection throw NetworkError, and addresses rejected by policy throw LFHttpUrlBlocked. Wrap calls in try/catch so one failure does not kill the whole app.