Rate limits
Every form has a per-IP rate limit. The same IP submitting the same form too fast gets a 429 Too Many Requests response. Real users almost never hit it; bots hammering one form do.
Limits are enforced before validation, before captcha, before anything expensive. A blocked request is cheap.
Default limits
| Plan | Submissions per IP per form | Window |
|---|---|---|
| Free | 30 | 60 seconds |
| Starter | 60 | 60 seconds |
| Pro | 120 | 60 seconds |
| Pro+ | 240 | 60 seconds |
These are sane defaults for a single contact form. A signup form behind a marketing campaign that legitimately receives bursts of traffic should be tuned higher (see below).
What a 429 looks like
HTTP/1.1 429 Too Many Requests
Retry-After: 42
Content-Type: application/json
{
"error": "rate_limited",
"message": "Too many submissions from this IP. Try again in 42 seconds.",
"retry_after": 42
}
The Retry-After header is in seconds and matches the retry_after field in the JSON body. Clients should respect it — retrying earlier just resets the cooldown.
For browser-side submissions, the response includes CORS headers so your fetch handler can read the body. Display a friendly "you're going too fast" message rather than a generic error.
Tuning per form
Per-form overrides live on the form's edit page under Rate limits:
- Max requests — integer, 1–10000.
- Window seconds — integer, 1–3600.
Set both to 0 to disable per-IP limits entirely (not recommended unless you have your own upstream limiter).
Tune the window first, the count second. A 10-second window with a count of 5 is much harsher than a 60-second window with a count of 30, even though both average 0.5/second.
Tuning per plan
If you're consistently hitting limits on legitimate traffic, upgrade. Higher plans get higher ceilings on the per-form cap and unlock larger window sizes.
The dashboard shows your rate limit hit count over the last 30 days on the form overview. If that number is low and you're still seeing spam, the bots are coming from too many IPs to limit by IP alone — switch to a captcha or AI moderation.
What doesn't count
- Authenticated REST API calls (those use a separate per-token limit).
- Webhook deliveries from Formspring to your endpoint (those are throttled by the queue).
- Submissions from the embed widget when the form has
disable_rate_limit_for_embedset (Pro+).
Handling 429 in your code
If you submit from JavaScript, parse the Retry-After header and back off:
async function submitForm(formId, data) {
const res = await fetch(`https://formspring.io/f/${formId}`, {
method: 'POST',
body: data
});
if (res.status === 429) {
const retryAfter = Number(res.headers.get('Retry-After') ?? 30);
throw new RateLimitError(`Try again in ${retryAfter}s`, retryAfter);
}
return res.json();
}
For server-side submissions, treat 429 as a hard failure — don't loop. If you're hitting the limit from a server (where retries are cheap), you're hitting the wrong limit; raise the per-form cap or use the authenticated REST API instead.