Created
March 14, 2026 19:42
-
-
Save ribtoks/c59a9fed190532bde91b947e97a5e80c to your computer and use it in GitHub Desktop.
Private Captcha Local e2e tutorial (Node.js version)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <title>Private Captcha Example</title> | |
| <style> | |
| body { | |
| display:flex; | |
| flex-direction: column; | |
| min-height: 100vh; | |
| } | |
| form { | |
| max-width: 32rem; | |
| margin: auto; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 20px; | |
| border: 1px #ccc solid; | |
| padding: 20px; | |
| } | |
| </style> | |
| <script defer src="https://cdn.privatecaptcha.com/widget/js/privatecaptcha.js"></script> | |
| <script type="text/javascript"> | |
| function onCaptchaSolved() { | |
| const submitButton = document.querySelector('#formSubmit'); | |
| submitButton.disabled = false; | |
| } | |
| </script> | |
| </head> | |
| <body> | |
| <div style="display: flex; flex: 1 1 0%"> | |
| <form action='/submit' method="POST"> | |
| <label> Email: </label> | |
| <input type="email" name="email" placeholder="Email address" required /> | |
| <div class="private-captcha" data-sitekey="your-sitekey" data-finished-callback="onCaptchaSolved"></div> | |
| <button id="formSubmit" type="submit" disabled> Submit </button> | |
| </form> | |
| </div> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const http = require('node:http'); | |
| const fs = require('node:fs'); | |
| async function checkSolution(solution, apiKey) { | |
| const response = await fetch('https://api.privatecaptcha.com/verify', { | |
| method: 'POST', | |
| headers: { 'X-Api-Key': apiKey }, | |
| body: solution | |
| }); | |
| const data = await response.json(); | |
| if (!data.success || data.code !== 0) { | |
| throw new Error('solution is not correct'); | |
| } | |
| } | |
| const resultPage = (color) => `<!DOCTYPE html><html><body style="background-color: ${color};"></body></html>`; | |
| const server = http.createServer(async (req, res) => { | |
| if (req.url === '/submit' && req.method === 'POST') { | |
| let body = ''; | |
| for await (const chunk of req) body += chunk; | |
| const formData = new URLSearchParams(body); | |
| const captchaSolution = formData.get('private-captcha-solution') ?? ''; | |
| try { | |
| await checkSolution(captchaSolution, 'your-api-key'); | |
| res.end(resultPage('green')); | |
| } catch (error) { | |
| res.end(resultPage('red')); | |
| } | |
| return; | |
| } | |
| if (req.url === '/' && req.method === 'GET') { | |
| fs.readFile('index.html', (err, html) => { | |
| if (err) { | |
| res.statusCode = 500; | |
| res.end('Internal Server Error'); | |
| return; | |
| } | |
| res.setHeader('Content-Type', 'text/html; charset=utf-8'); | |
| res.end(html); | |
| }); | |
| return; | |
| } | |
| res.statusCode = 404; | |
| res.end('Not found'); | |
| }); | |
| server.listen(8081, () => { | |
| console.log('Listening on http://localhost:8081/'); | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment