Bun's built-in fetch makes a scraper trivial to write, but the crawl's dedupe set is worthless if it evaporates on every redeploy. DenkOps attaches a durable /persist disk to the slot, so a Hono-triggered scraper can keep a JSON index of visited URLs on disk and skip pages it already has the next time it runs.
import { Hono } from "hono";
const app = new Hono();
const STATE = "/persist/seen.json";
app.post("/scrape", async (c) => {
const seen: string[] = await Bun.file(STATE).exists() ? await Bun.file(STATE).json() : [];
const res = await fetch("https://example.com/listings");
const html = await res.text();
const links = [...html.matchAll(/href="(\/listing\/[^"]+)"/g)].map((m) => m[1]);
await Bun.write(STATE, JSON.stringify([...new Set([...seen, ...links])]));
return c.json({ total: links.length });
});
export default { port: 3000, fetch: app.fetch };Deploy it: install the plugin, say "deploy on DenkOps", and get a live SSL URL.
Start on DenkOps →Yes, Bun.write to /persist survives restarts and redeploys, so your seen-URL set carries over instead of resetting to empty.
Yes, through the zero-trust egress gateway, which permits and logs outbound HTTP calls so your scraper can reach any target.