Ask Anvil

Answers to questions about automating PDFs, e-signatures, Webforms, and other paperwork problems.
Webforms
Categories

How do I let someone save a web form and finish it later?

Store the partial answers server-side under a submission ID, then give the user a signed, expiring link that points at that ID. Keep the answers themselves out of the link.

const crypto = require('crypto');

const SECRET = process.env.FORM_RESUME_SECRET;   // 32+ random bytes, not in source
const TTL_MS = 7 * 24 * 60 * 60 * 1000;          // links die after 7 days

function makeResumeToken(submissionId) {
  const payload = Buffer.from(
    JSON.stringify({ id: submissionId, exp: Date.now() + TTL_MS })
  ).toString('base64url');
  const sig = crypto.createHmac('sha256', SECRET).update(payload).digest('base64url');
  return `${payload}.${sig}`;
}

function readResumeToken(token) {
  const [payload, sig] = String(token).split('.');
  if (!payload || !sig) return null;
  const expected = crypto.createHmac('sha256', SECRET).update(payload).digest('base64url');
  const a = Buffer.from(sig), b = Buffer.from(expected);
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) return null;
  const data = JSON.parse(Buffer.from(payload, 'base64url').toString());
  return Date.now() > data.exp ? null : data.id;
}

module.exports = { makeResumeToken, readResumeToken };

What the server does with it

On each autosave the browser posts the current answers, and the server upserts them into a row keyed by the submission ID. When the user asks for a resume link, or you email one after they abandon the form, call makeResumeToken(submissionId) and build a URL like https://example.com/forms/resume?t=TOKEN.

When someone opens that URL, run readResumeToken on the query parameter. A null result means the token was tampered with, has expired, or was signed with a secret you have since rotated, so render a fresh form rather than an error page. A non-null result hands you the submission ID, which you load and render back into the form.

Two things to get right

Autosave on a debounce, not on every keystroke. A request per character will hammer your write path and race itself. Save when a field loses focus, or on a two to three second idle timer, and make the save idempotent so a retried request updates the existing row instead of creating a second one.

Treat the resume link as a credential. Anyone holding the URL holds the partial answers, and URLs leak through shared inboxes, browser history, and referrer headers. Keep the TTL short, scope each token to exactly one submission, and if the form collects anything sensitive (bank details, a government ID number, health information), make the user re-authenticate before you render the saved values back. Rotating the signing secret invalidates every outstanding link at once, which is the lever you want if one is ever exposed.

Back to All Questions

The fastest way to build software for documents

Anvil Document SDK is a comprehensive toolbox for product teams launching document flows where PDF filling, signing, and complex conditional scenarios are necessary.
Explore Anvil
Anvil Webforms