Skip to content
Back to skills

1228 Patterns 7d229cb9

ASecurity

```html <!DOCTYPE html> <html> <head> <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script> </head> <body> <form action="/submit" method="POST"> <input type="email" name="email" required> <div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY"></div> <button type="submit">Submit</button> </form> </body> </html> ```

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
developmentjavascripttypescriptjavareactvuenodetestingapi

Works with

  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 1228-patterns_7d229cb9 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 1228 Patterns 7d229cb9?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 1228 Patterns 7d229cb9
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-1228-patterns-7d229cb9/badge)](https://www.skillsdirectory.com/skills/tools-only-1228-patterns-7d229cb9)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Common Patterns

## Form Integration

### Basic Form (Implicit Rendering)

```html
<!DOCTYPE html>
<html>
<head>
  <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
</head>
<body>
  <form action="/submit" method="POST">
    <input type="email" name="email" required>
    <div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY"></div>
    <button type="submit">Submit</button>
  </form>
</body>
</html>
```

### Controlled Form (Explicit Rendering)

```javascript
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"></script>
<script>
let widgetId = window.turnstile.render('#container', {
  sitekey: 'YOUR_SITE_KEY',
  callback: (token) => console.log('Token:', token)
});

form.addEventListener('submit', async (e) => {
  e.preventDefault();
  const token = window.turnstile.getResponse(widgetId);
  if (!token) return;
  
  const response = await fetch('/submit', {
    method: 'POST',
    body: JSON.stringify({ 'cf-turnstile-response': token })
  });
  
  if (!response.ok) window.turnstile.reset(widgetId);
});
</script>
```

## Framework Patterns

### React

```tsx
import { useState } from 'react';
import Turnstile from '@marsidev/react-turnstile';

export default function Form() {
  const [token, setToken] = useState<string | null>(null);

  return (
    <form onSubmit={async (e) => {
      e.preventDefault();
      if (!token) return;
      await fetch('/api/submit', { 
        method: 'POST',
        body: JSON.stringify({ 'cf-turnstile-response': token })
      });
    }}>
      <Turnstile siteKey="YOUR_SITE_KEY" onSuccess={setToken} />
      <button disabled={!token}>Submit</button>
    </form>
  );
}
```

### Vue / Svelte

```vue
<!-- Vue: npm install vue-turnstile -->
<VueTurnstile :site-key="SITE_KEY" @success="token = $event" />

<!-- Svelte: npm install svelte-turnstile -->
<Turnstile siteKey={SITE_KEY} on:turnstile-callback={(e) => token = e.detail.token} />
```

## Server Validation

### Cloudflare Workers

```typescript
interface Env {
  TURNSTILE_SECRET: string;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    if (request.method !== 'POST') {
      return new Response('Method not allowed', { status: 405 });
    }
    
    const formData = await request.formData();
    const token = formData.get('cf-turnstile-response');
    
    if (!token) {
      return new Response('Missing token', { status: 400 });
    }
    
    // Validate token
    const ip = request.headers.get('CF-Connecting-IP');
    const result = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        secret: env.TURNSTILE_SECRET,
        response: token,
        remoteip: ip
      })
    });
    
    const validation = await result.json();
    
    if (!validation.success) {
      return new Response('CAPTCHA validation failed', { status: 403 });
    }
    
    // Process form...
    return new Response('Success');
  }
};
```

### Pages Functions

```typescript
// functions/submit.ts - same pattern as Workers, use ctx.env and ctx.request
export const onRequestPost: PagesFunction<{ TURNSTILE_SECRET: string }> = async (ctx) => {
  const token = (await ctx.request.formData()).get('cf-turnstile-response');
  // Validate with ctx.env.TURNSTILE_SECRET (same as Workers pattern above)
};
```

## Advanced Patterns

### Pre-Clearance (Invisible)

```html
<div id="turnstile-precheck"></div>
<form id="protected-form" style="display: none;">
  <button type="submit">Submit</button>
</form>

<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"></script>
<script>
let cachedToken = null;

window.onload = () => {
  window.turnstile.render('#turnstile-precheck', {
    sitekey: 'YOUR_SITE_KEY',
    size: 'invisible',
    callback: (token) => {
      cachedToken = token;
      document.getElementById('protected-form').style.display = 'block';
    }
  });
};
</script>
```

### Token Refresh on Expiry

```javascript
let widgetId = window.turnstile.render('#container', {
  sitekey: 'YOUR_SITE_KEY',
  'refresh-expired': 'manual',
  'expired-callback': () => {
    console.log('Token expired, refreshing...');
    window.turnstile.reset(widgetId);
  }
});
```

## Testing

### Environment-Based Keys

```javascript
const SITE_KEY = process.env.NODE_ENV === 'production'
  ? 'YOUR_PRODUCTION_SITE_KEY'
  : '1x00000000000000000000AA'; // Always passes

const SECRET_KEY = process.env.NODE_ENV === 'production'
  ? process.env.TURNSTILE_SECRET
  : '1x0000000000000000000000000000000AA';
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.