A Deno-built, installable Violentmonkey userscript for Startpage web-result pages. It retrieves the first configured number of ordinary web results through Jina Reader, sends successful source Markdown to an OpenAI-compatible /v1/chat/completions API, and renders a sanitised, citation-restricted answer above the results.
The project intentionally uses Deno only. It has no Node, npm, pnpm, or Bun project commands.
deno task buildThis produces dist/startpage-ai-summary.user.js; install that file through Violentmonkey.
Deno resolves the pinned npm: dependencies declared in deno.json as part of its own dependency system. nodeModulesDir: "auto" is set because esbuild resolves application imports using its Node-compatible resolver; Deno creates and manages the local node_modules/ directory automatically. Do not use npm, pnpm, Bun, or Node commands. The dependencies are bundled into the generated userscript, which has no runtime CDN imports or @require dependencies.
src/startpage-ai-summary.ts— application lifecycle, UI state, hotkey, and orchestrationsrc/settings.ts— Violentmonkey Values schema/defaultssrc/startpage.ts— narrowly scoped Startpage query/result extractionsrc/network.ts— Jina and OpenAI requests, cancellation, concurrencysrc/prompt.ts— source-delimited model promptsrc/render.ts— markdown sanitisation, citation reconstruction, usage costsrc/styles.ts— isolatedspai-*stylingsrc/types.ts— shared types
Open Violentmonkey's dashboard, select this script, then use its Values storage to set one settings object. The values are held by Violentmonkey's extension storage and are not available to Startpage page JavaScript. Do not enter the API key anywhere in Startpage.
Example:
{
"openaiBaseUrl": "https://api.openai.com",
"openaiApiKey": "sk-...",
"openaiModel": "gpt-5.4",
"jinaApiKey": "jina_...",
"jinaEngine": "cf-browser-rendering",
"resultLimit": 8,
"maxCharsPerResult": 12000,
"maxConcurrentJinaRequests": 8,
"jinaTimeoutMs": 4000,
"openaiTimeoutMs": 10000,
"maxCompletionTokens": 2000,
"hotkey": "Alt+A",
"showUsageAndCost": true,
"inputPricePerMillionUsd": 0,
"outputPricePerMillionUsd": 0
}The script’s reset menu command writes the defaults, which can be used to initialize the Value. Its defaults are the values above except openaiApiKey, openaiModel, and jinaApiKey, which are empty. jinaEngine defaults to cf-browser-rendering and can be changed in the settings object.
The metadata initially grants privileged cross-origin access only to r.jina.ai and api.openai.com. You may change openaiBaseUrl through Violentmonkey Values to any HTTPS OpenAI-compatible provider. To make that work, explicitly add the provider hostname as another @connect line in build.ts, rebuild, and reinstall the generated userscript. The script does not contain an API-host allowlist beyond Violentmonkey's @connect permission.
- API credentials are read only with
GM_getValue; they are not put into DOM nodes, attributes, page storage, URLs, console logs, or errors shown in the page. - Result URLs are parsed, and only
http:andhttps:results are selected. Jina requests always use the fixedhttps://r.jina.ai/origin. When configured,jinaApiKeyis sent only to that origin asAuthorization: Bearer …; Jina requests always sendDNT: 1,X-Retain-Images: none, andX-Return-Format: markdown, whileX-Engineuses the configurablejinaEngine. - The answer is parsed by
markdown-itwith raw HTML disabled and then sanitised by DOMPurify with a restrictive tag/attribute allowlist. - No model-provided links or images are rendered. Only valid
[^N]citation markers become links, and their destinations are reconstructed exclusively from the selected Startpage result URL for sourceN. - The script adds only its own
spai-*UI nodes. It identifies the Startpage Web results root from.w-gl-attributionand result title links froma[data-testid="gl-title-link"].
Jina receives selected result URLs. The configured OpenAI provider receives the query and retrieved source text. Source failures are tolerated: the summary is generated from the successful retrievals only, and the panel reports the retrieved count.