Day 04: Spam Protection & Deployment Switch
Today started with adding spam protection to the assessment form using Cloudflare Turnstile, but quickly evolved into a bigger architectural decision - switching from Sevalla Static Sites to Vercel to enable secure server-side form handling.
Try it yourself: Assessment Form
What Got Done
Cloudflare Turnstile Integration
Integrated Cloudflare Turnstile as a privacy-friendly CAPTCHA alternative:
- Widget Rendering: Turnstile widget loads dynamically on the final assessment step
- Token Validation: Submission requires a valid Turnstile token before proceeding
- Error Handling: Graceful error states if verification fails
- Environment Configuration: Site key configured via
PUBLIC_TURNSTILE_SITE_KEYenvironment variable
Implementation Details
The Turnstile integration lives in the Assessment.tsx component:
// Load Turnstile script and render widget on final step
useEffect(() => {
const isLastStep = state.currentStep === totalQuestions;
if (!isLastStep) {
// Clean up widget if navigating away from last step
if (turnstileWidgetId.current && window.turnstile) {
window.turnstile.remove(turnstileWidgetId.current);
turnstileWidgetId.current = null;
}
return;
}
// Load and render Turnstile widget
renderTurnstile();
}, [state.currentStep, totalQuestions]);
Key features:
- Widget only appears on the final step
- Proper cleanup when navigating away
- Token captured via callback
- Submit button disabled until verification completes
Testing
Added unit tests to verify Turnstile integration:
- Widget renders on final step
- Submission requires valid token
- Error states handled properly
- Token capture works correctly
The Deployment Platform Switch
Why the Change?
The original plan was to deploy on Sevalla Static Sites (free tier), but Turnstile integration revealed a critical limitation: Sevalla Static Sites don’t support server-side rendering (SSR) or serverless functions.
This created a security problem:
The Issue:
- Turnstile tokens must be verified server-side for security
- Sevalla Static Sites are purely static - no SSR support
- Sevalla Applications (which support SSR) are not free
- Without SSR, I’d need to expose API keys in the browser
- Or use a third-party proxy like Formspree (limited to 50 submissions/month)
- Neither option was acceptable for a production site
The Solution: Switch to Vercel, which offers:
- ✅ Full SSR support with Astro
- ✅ Serverless functions for API routes
- ✅ Server-side Turnstile verification
- ✅ Secure Resend API integration
- ✅ 1 million function invocations/month (free tier)
- ✅ All API keys stay server-side
- ✅ Still completely free
What Changed
Configuration:
- Added
@astrojs/verceladapter withoutput: 'server' - Static pages marked with
export const prerender = truefor performance - Created
/api/submitserverless function for form handling
Form Submission Flow:
Browser → /api/submit (serverless) → Verify Turnstile → Resend API → Email
Security Improvements:
- Server-side Turnstile verification - tokens verified before processing
- API keys never exposed - all secrets stay on server
- No client-side API calls - no risk of key exposure in browser
Cost Comparison
Sevalla Static Sites (Free):
- 600 build minutes/month
- 100 GB bandwidth/month
- ❌ No serverless functions
- ❌ No SSR support
Sevalla Applications (Paid):
- ✅ SSR support
- ✅ Serverless functions
- 💰 Not free (would need to upgrade)
Vercel Hobby (Free):
- 1 million function invocations/month
- 4 hours Active CPU time/month
- 360 GB-hours Provisioned Memory/month
- 100 GB bandwidth/month
- ✅ Full SSR + serverless functions
- ✅ Completely free
The Vercel free tier is more than sufficient for this project’s needs, and keeps the entire project cost at $0.
Environment Setup
To use Turnstile with Vercel, you need to:
- Get your site key from Cloudflare Dashboard
- Add to Vercel environment variables:
PUBLIC_TURNSTILE_SITE_KEY=your_site_key_here TURNSTILE_SECRET_KEY=your_secret_key_here RESEND_API_KEY=your_resend_api_key_here
Important: Don’t use PUBLIC_ prefix for secrets (TURNSTILE_SECRET_KEY, RESEND_API_KEY).
Lessons Learned
- Platform limitations matter - Always verify your hosting platform supports your architecture before committing
- Security first - Never compromise on security for convenience or cost
- Free tiers can be generous - Vercel’s free tier is actually more capable than many paid static hosting options
- SSR isn’t always needed - But when you need it, you really need it
What’s Next
With the deployment platform sorted and Turnstile integrated, Day 5 will focus on completing the form submission flow and testing the entire assessment experience end-to-end.