fetch can POST JSON. That is not permission to paste a Trends API key into a <script> tag. The call shape is POST https://api.trendsapi.ai/api with a Bearer header. The envelope's body is a JSON string and must be parsed a second time. A page that needs a chart should fetch a same-origin route that holds the key. Docs: the API reference. Caps: pricing. Live Google board notes: the Google Trends guide.
fetch in a page, not Node
// Runs on a server or a trusted same-origin route. Not in a public bundle.
export async function trendingNow() {
const resp = await fetch("https://api.trendsapi.ai/api", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TRENDSAPI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
mode: "get_top_trends",
type: "Google Trends",
limit: 10,
}),
});
if (!resp.ok) {
throw new Error(`http ${resp.status}`);
}
const outer = await resp.json();
return JSON.parse(outer.body);
}
process.env here assumes a bundler that only runs on the server. In a raw browser script that object does not exist. That is a hint the key is in the wrong place.
Where the key must not live
Public JS, GitHub gists, CodePen, and client-side .env files that ship to the CDN are all leaks. Rotate the key if it was pasted into a gist. Issue a new one from the account flow. Limits: pricing.
response.json then JSON.parse on body
outer.statusCode is the inner status. outer.body is text. JSON.parse(outer.body) yields the board rows or the series. A UI that JSON.stringify(outer) into a <pre> is still showing the unparsed string.
CORS and why a browser tab is the wrong host
A local HTML file opening api.trendsapi.ai will hit CORS and a leaked-key problem at once. The fix is not a browser plugin. The fix is a 20-line route on the site the user is already on. The product MCP server at https://api.trendsapi.ai/mcp is for agents, not for file://.