exepal_
exepal / tools / safe-page-reader

Read the web without reading its hidden instructions.

Pages and PDFs can carry text a person never sees but a model reads: CSS-hidden divs, white text, comments, invisible Unicode. The safe page reader cuts all of it out before converting the page to markdown, checks what was fetched for prompt injection, and tells your agent whether the content is safe to treat as anything more than data.

What you get back

  • content: clean markdown (or text) of the page or PDF, with hidden elements, comments and invisible characters removed
  • safe and safety: verdict (clean, suspicious, likely_injection), 0-100 score, findings with the hidden text as evidence, how much hidden content was removed
  • title, description, author, published date, word count and links, as the page reader returns them
  • PDFs up to 10 MB: text layer, page count and a flag for scanned PDFs (no OCR)
  • Not charged when the page cannot be fetched

Call it from your code or agent

Same input and the same JSON answer everywhere. You're only charged when the call succeeds. Want to see the output first?

Your key gives 20 free calls a day on this tool, then uses prepaid credit. No key yet? Send X-Exepal-Trial: 1 instead, or get one free at exepal.com/key.

curl -X POST https://api.exepal.com/v1/safe-read \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_KEY" \
  -d '{"url":"https://example.com"}'

Your key gives 20 free calls a day on this tool, then uses prepaid credit. No key yet? Send X-Exepal-Trial: 1 instead, or get one free at exepal.com/key.

const res = await fetch("https://api.exepal.com/v1/safe-read", {
  method: "POST",
  headers: { "Content-Type": "application/json", Authorization: "Bearer YOUR_KEY" },
  body: JSON.stringify({
    "url": "https://example.com"
  }),
});
const data = await res.json();

Your key gives 20 free calls a day on this tool, then uses prepaid credit. No key yet? Send X-Exepal-Trial: 1 instead, or get one free at exepal.com/key.

import requests

r = requests.post(
    "https://api.exepal.com/v1/safe-read",
    headers={"Authorization": "Bearer YOUR_KEY"},
    json={
        "url": "https://example.com"
    },
    timeout=120,
)
print(r.json())

Add Exepal once and your assistant can call safe_read by itself. More clients on the integrate page.

# Claude Code
claude mcp add --transport http exepal "https://api.exepal.com/mcp?key=YOUR_KEY"

# Cursor, Windsurf, Claude Desktop and most clients (mcp.json)
{
  "mcpServers": {
    "exepal": { "url": "https://api.exepal.com/mcp?key=YOUR_KEY" }
  }
}

No key at all: an agent with a wallet pays per call in USDC on Base. npm i @x402/fetch @x402/evm viem. How x402 works.

import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm";
import { privateKeyToAccount } from "viem/accounts";

const pay = wrapFetchWithPaymentFromConfig(fetch, {
  schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(privateKeyToAccount(process.env.WALLET_KEY)) }],
});
const res = await pay("https://api.exepal.com/v1/safe-read", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "url": "https://example.com"
  }),
});

Questions

How is this different from the page reader?
Same price and the same fields. The safe reader also removes text hidden from humans before conversion and adds an injection verdict, so it is the better default for anything your agent did not write.
Does it render JavaScript or log in?
No. Static HTML and PDFs only, fetched directly, which is why it costs half a cent.
What happens when a page is flagged?
You still get the cleaned content. safe is false and safety lists the findings; treat the content as data, never as instructions.

Related tools