The dripdex manual

Publish an HTML page, get back a link that only people with its password can open. No account, no signup.

You publish at
https://dripdex.ai
People read at
https://dripdex.app/p/<slug>

What you get

Hand dripdex an HTML page — dropped in a browser, POSTed, or published by an agent — and you get back two things:

url
https://dripdex.app/p/7p2wr6gq33
password
otter-lantern-brisk-copper-mint

The URL is not the secret. The password is the access control, it is checked on the server, and it is shown to you exactly once. Only a hash of it is stored, so nothing and nobody can read it back afterwards — not support, not the API, not the database. If you lose it, you rotate it; you do not recover it.

Give whoever you are sending it to both. A page whose password was not passed on is a page nobody can open.

There is one tier. Nothing here is raised by paying.

What a page may contain

HTML and CSS only. These are not style preferences — they are enforced when the page is ingested, and content that breaks them is removed. Every removal is reported back to you.

FineRemoved
HTML, inline <style>, style attributesJavaScript of any kind: <script>, on* handlers, javascript: URLs
Images, fonts and CSS from inside your own uploadAnything loaded from elsewhere: remote <img>, webfont CDN, external stylesheet, @import
data: URIs<iframe> to another site, <base>, <meta http-equiv=refresh>, form actions
Links out — <a href>, mailto:SVG containing <script> or <foreignObject>
The no-external-files rule is the point of the product, not a performance preference. A remote <img> on a private page reports who opened it, and when, to whoever serves that image. Upload the file with the page instead, or inline it as a data: URI.

File types accepted: .html .htm .css .png .jpg .jpeg .gif .webp .avif .svg .ico .woff .woff2. Anything else is rejected.

Write a complete document: doctype, <meta charset="utf-8">, a <title>, and enough CSS that it reads well on a phone.

Publish it

Four ways in. They are the same thing underneath — a page published one way is identical to a page published another.

In a browser

  1. Drop your files on the box, or click it to pick them.
  2. Optionally set a title (defaults to Untitled) or type your own password instead of the generated one.
  3. The next screen gives you the link and the password.

No account and no sign-up. Two conveniences worth knowing:

A single HTML file just works

A multi-file upload needs an index.html, but dropping deck.html on its own renames it and tells you so, rather than refusing over a filename.

One browser is one account

Your first drop quietly creates an anonymous account, so later drops land in the same place and the page can list — and delete — what you have already dropped.

This is the door to send a person to. Point them here rather than explaining curl to them.

With one API call

curl -X POST https://dripdex.ai/v1/pages \
  -H 'content-type: application/json' \
  -d '{"html":"<!doctype html><h1>Q4</h1>","title":"Q4 deck"}'

Response (201):

{
  "url":       "https://dripdex.app/p/7p2wr6gq33",
  "password":  "otter-lantern-brisk-copper-mint",
  "pageId":    "…",
  "slug":      "7p2wr6gq33",
  "token":     "dd_live_…",
  "tokenNote": "Save this. It is shown once and cannot be recovered."
}

Build the JSON with a tool rather than by hand — HTML is full of quotes and backslashes, and a hand-escaped -d string breaks on the first one:

jq -Rs --arg t "Q4 deck" '{html:., title:$t}' page.html \
  | curl -sS -X POST https://dripdex.ai/v1/pages \
      -H 'content-type: application/json' \
      ${DRIPDEX_TOKEN:+-H "authorization: Bearer $DRIPDEX_TOKEN"} -d @-

password is generated unless you supply one, and is returned either way. token comes back on the first call only — see Your account is a token.

There is no list endpoint: the API can create, update and delete a page, not enumerate your pages.

From the command line

dripdex publish deck.html
# https://dripdex.app/p/7p2wr6gq33
# password: otter-lantern-brisk-copper-mint

cat deck.html | dripdex publish - --json | jq -r .url
CommandDoes
dripdex publish <file.html>Publish a new page. - reads stdin.
dripdex update <page-id> [file.html]Replace the content, retitle, or rotate the password.
dripdex rm <page-id>Delete a page.

Options: --title, --password, --rotate, --json, --api <origin>.

Your token is saved to ~/.dripdex/config.json on the first publish and reused after. $DRIPDEX_TOKEN overrides it. Everything except the result goes to stderr, so --json on stdout stays pipeable.

From an AI agent

Agents can publish for you. There are three paths, in order of preference.

  1. The API. Any agent that can reach the network makes the POST above. The instructions it needs are served at dripdex.ai/llms.txt — point an agent there and it can do the rest itself.
  2. MCP, when the agent's sandbox has no network. https://dripdex.ai/mcp is a single Streamable HTTP endpoint exposing three tools:
    publish_page(html, title?, password?)
    update_page(pageId, html?, title?, password?, rotatePassword?)
    delete_page(pageId)
    No account, no OAuth, no key. Protocol revisions 2025-03-26 through 2026-07-28 are all served on the one endpoint. This works where the agent's own request does not, because a connector is called by the agent's client, outside the sandbox. The agent cannot add it — you add https://dripdex.ai/mcp to your client's connectors, once.
  3. The handoff. With neither, a well-instructed agent writes index.html where you will receive it and sends you to dripdex.ai to drop it yourself. It should then stop — the password is shown once, on your screen, so an agent that reports a URL and password it never saw has invented them.
If the agent's sandbox uses an allowlist rather than a wall, one host is enough: dripdex.ai. The reading domain is for your recipients and never needs to be reachable from the sandbox.

Share the link

Send the URL and the password. That is the whole handover; there is nothing to invite, provision, or add to a team.

Passwords are five words — otter-lantern-brisk-copper-mint — because this string gets read off one screen and typed into another, dictated on a call, and copied out of a chat by hand. A typo in it is a misspelt word rather than an invisible character swap.

If you would rather choose your own, pass one at publish time. It is stored the same way and is equally unrecoverable.

Opening a page

What your recipient does:

  1. Opens the link and gets a password box. No account, nothing to install.
  2. Types the password. It is checked on the server — the page's bytes are never sent to a browser that has not unlocked.
  3. Stays unlocked for 7 days on that one page, then enters it again.

Guessing is metered: 10 attempts per person per page per 10 minutes, and 200 per page per hour across everyone.

A link that names nothing, a page belonging to someone else, and a deleted page all answer the same blank “not found”. That is deliberate: it means these URLs cannot be used to discover which pages exist.

Change or delete a page

All three need your token. There is no anonymous way to change a page.

# replace the content — the link and password are unchanged
curl -X PATCH https://dripdex.ai/v1/pages/<pageId> \
  -H "authorization: Bearer $DRIPDEX_TOKEN" -H 'content-type: application/json' \
  -d '{"html":"<!doctype html><h1>Revised</h1>"}'

# rotate the password — the old one stops working immediately
curl -X PATCH https://dripdex.ai/v1/pages/<pageId> \
  -H "authorization: Bearer $DRIPDEX_TOKEN" -H 'content-type: application/json' \
  -d '{"rotatePassword":true}'

# delete
curl -X DELETE https://dripdex.ai/v1/pages/<pageId> \
  -H "authorization: Bearer $DRIPDEX_TOKEN"
dripdex update <page-id> revised.html --title "v2"
dripdex update <page-id> --rotate
dripdex rm <page-id>

PATCH takes any subset of html, title, password, rotatePassword. An empty patch is an error rather than a silent no-op, and the response reports what actually changed rather than echoing what you asked for.

Four behaviours to plan around:

The link never changes

Sending new html publishes a new version behind the same URL, so a link you already sent a client keeps working and starts showing the new content.

Rotating cuts off people already reading

Not just future visitors. Anyone currently viewing loses access on their next click.

A reader unlocking at the same moment may be asked once more

If they unlock in the same few seconds you change the password. That is the system erring toward locked, which is the right direction.

Delete is immediate and total

The link stops working for everyone, including people already reading.

Your account is a token

The token is the whole credential. dd_live_… is returned exactly once, on the first call that creates your account, and only a hash of it is kept. There is no password reset, because there is no account to reset.

The email field is not a login. Typing an address records a claim on that upload — nothing more. It does not sign you in and it cannot reach an account that already exists. A claim becomes ownership only when a link sent to that address is opened, which is the one piece of evidence this system will accept that the address is yours; your pages then move to the verified account.

This deployment does not send mail yet, so nothing can be verified and claims simply wait. The drop page says as much rather than implying a link it cannot send.

Limits

LimitValueNotes
Page size4 MiBThrough every door. Measured as UTF-8 bytes of what you send.
Request body (API)5 MiBRejected before the page is even looked at.
Files per upload50
New pages30 per dayRolling, per account — see below.
Publishes per hour60
Unlock attempts10 / person / page / 10 min
200 / page / hour
Stays unlocked7 daysPer page, per reader.

The 30 a day is a rolling window, not a midnight reset. Each page frees its own slot 24 hours after you create it. There is no cap on how many pages an account holds in total, and deleting a page does not buy back an allowance — the budget is spent on creation, so a page you deleted still counted. One tier, no paid upgrade: nothing raises either number.

The page size is not a pricing decision. A page reaches this service inside a single request payload capped at 6 MiB, measured after the transport re-encodes your request into it — 4 MiB is what survives that for every shape of HTML. The API's 5 MiB body cap sits a little above the page ceiling because escaping a full-size page into JSON costs more than the page itself.

Inline data: URIs count in full, and base64 is about a third larger than the bytes it carries, so images are what put a page over, essentially always. Too big is not something to retry — downscale images to the width they are actually displayed at, re-encode photographs as JPEG or WebP, and use SVG for anything drawn. Publishing an oversized page and then patching a smaller one still spends the quota on the failed attempt.

Errors

JSON, with a stable code.

StatuscodeMeans
400html-required, title-invalid, password-invalid, rotate-password-invalidBad request body
400nothing-to-updateEmpty PATCH
401unauthorizedUnknown or revoked token
413content-rejectedOver the size cap, or body over 5 MiB
422content-rejectedRejected on ingest; details says exactly what and where
429rate-limitedToo fast, or the day's 30 pages are spent; carries Retry-After
404not-found, goneNo such page, not yours, or already deleted

A page belonging to another account answers 404, identically to one that never existed. That is deliberate and not a bug to work around.

Troubleshooting

My images or fonts don't show up

They pointed at another site and were removed. Upload them together with the page, or inline them as data: URIs. The publish response lists every removal with the file and element involved.

My page looks unstyled

An external stylesheet or @import went the same way. Move the CSS into a <style> block, or upload the .css file with the page.

The interactive parts are gone

Correct, and permanent: no JavaScript, ever. That constraint is what makes a hosted page safe to open. You can still do a surprising amount with CSS alone — :target, :checked, <details> — or publish a few linked pages.

422 content-rejected

Read details. It names the reason (external-resource, script-element, and so on), the file, and the element or attribute.

413, or an error with nothing in it

The page is too big. Shrink the images; do not retry as-is.

429

Check Retry-After. Your allowance frees up as your earliest pages of the day pass 24 hours old. Nothing raises it — there is one tier.

404 on a page I published

Either this call used a different token than the one that published it, or the page was deleted. The two are indistinguishable on purpose.

I lost the password

It cannot be recovered. Rotate it — --rotate, or {"rotatePassword":true} — and send the new one out. Everyone currently reading loses access.

I lost the token

Your pages keep serving; you can no longer update or delete them. New publishes will start a fresh account unless you are in the browser that holds the cookie.

Ready? Drop a page at dripdex.ai. What we keep, and for how long: privacy.