Files
dotfiles/dot_claude/skills/turnstile-spin/references/astro.md
T
Prad NukalaandClaude Fable 5 20891f3910 config(git,claude,ssh): templated gitconfig; claude settings/commands/hooks/skills; ssh config
gitconfig: name/email from chezmoi data, gh credential helper by PATH
lookup (portable to darwin). claude: no credentials, history, projects,
sessions, or plugin caches. ssh config as private_ (0600).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-09 14:53:46 -04:00

2.4 KiB

Astro

For Astro projects. The form posts directly to the Worker. Astro frontmatter handles config substitution at build time.

---
const WORKER_URL = import.meta.env.PUBLIC_TURNSTILE_WORKER_URL;
const SITEKEY = import.meta.env.PUBLIC_TURNSTILE_SITEKEY;
---

<html>
	<head>
		<script
			src="https://challenges.cloudflare.com/turnstile/v0/api.js"
			async
			defer
		></script>
	</head>
	<body>
		<form action={`${WORKER_URL}/`} method="POST">
			<input name="email" type="email" required />
			<div
				class="cf-turnstile"
				data-sitekey={SITEKEY}
				data-action="turnstile-spin-v1"
			/>
			<button type="submit">Sign up</button>
		</form>
	</body>
</html>

In your .env:

PUBLIC_TURNSTILE_WORKER_URL=https://YOUR_WORKER_URL
PUBLIC_TURNSTILE_SITEKEY=YOUR_SITEKEY

The PUBLIC_ prefix is mandatory for client-exposed variables in Astro.

Variant: hardcoded values

If you do not use env vars, inline directly:

<html>
	<head>
		<script
			src="https://challenges.cloudflare.com/turnstile/v0/api.js"
			async
			defer
		></script>
	</head>
	<body>
		<form action="https://YOUR_WORKER_URL/" method="POST">
			<div
				class="cf-turnstile"
				data-sitekey="YOUR_SITEKEY"
				data-action="turnstile-spin-v1"
			/>
			<button type="submit">Sign up</button>
		</form>
	</body>
</html>

Variant: Astro Actions

If the project uses Astro Actions, call siteverify from the action:

import { defineAction } from "astro:actions";
import { z } from "astro:schema";

export const server = {
	signup: defineAction({
		accept: "form",
		input: z.object({
			email: z.string().email(),
			"cf-turnstile-response": z.string(),
		}),
		handler: async (input) => {
			const verify = await fetch("https://YOUR_WORKER_URL/", {
				method: "POST",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({ token: input["cf-turnstile-response"] }),
			});
			const data = await verify.json();
			if (!data.success) throw new Error("Verification failed");
			// process signup
		},
	}),
};

Substitutions

Placeholder Replace with
YOUR_WORKER_URL Deployed Worker URL from Step 5
YOUR_SITEKEY Widget site key from Step 4