gif-captcha core library โ v1.0.0
npm install gif-captcha
const gifCaptcha = require("gif-captcha");
// or
import gifCaptcha from "gif-captcha";
<script src="https://unpkg.com/gif-captcha/src/index.js"></script>
<script>
// Available as window.gifCaptcha
const challenge = gifCaptcha.createChallenge({ ... });
</script>
Escape a string for safe insertion into innerHTML. Uses DOM-based escaping in browsers, regex-based escaping in Node.js.
| Param | Type | Description |
|---|---|---|
str | string | Untrusted input to escape |
gifCaptcha.sanitize('<script>alert(1)</script>');
// โ "<script>alert(1)</script>"
gifCaptcha.sanitize('Hello "world" & friends');
// โ 'Hello "world" & friends'
Create a standalone sanitizer instance. Useful when you need isolated sanitizers or want to avoid the global default.
const mySanitizer = gifCaptcha.createSanitizer();
mySanitizer.sanitize('<b>bold</b>');
// โ "<b>bold</b>"
Load a GIF image into a DOM container with automatic retry on failure. On final failure, shows a fallback with a link to the source or a title hint. Browser-only.
| Param | Type | Description |
|---|---|---|
container | HTMLElement | DOM element to render into |
challenge | Object | Challenge object with title, gifUrl, and optional sourceUrl |
attempt | number | Current attempt index (0-based, default 0) |
const container = document.getElementById('captcha-gif');
gifCaptcha.loadGifWithRetry(container, {
title: "Surprise Ending",
gifUrl: "https://example.com/twist.gif",
sourceUrl: "https://example.com/source"
});
Calculate word-level Jaccard similarity between two strings. Returns a score between 0 (no overlap) and 1 (identical words). Case-insensitive.
| Param | Type | Description |
|---|---|---|
a | string | First string |
b | string | Second string |
gifCaptcha.textSimilarity("the cat sat on the mat", "the cat sat");
// โ 0.833 (5/6 unique words overlap)
gifCaptcha.textSimilarity("hello world", "goodbye moon");
// โ 0 (no shared words)
Validate a user's CAPTCHA response against the expected answer using fuzzy text matching and optional keyword checks.
| Param | Type | Description |
|---|---|---|
userAnswer | string | The user's typed response |
expectedAnswer | string | The correct/expected answer |
options.threshold | number | Minimum similarity score to pass (default: 0.3) |
options.requiredKeywords | string[] | Words that must appear in the answer (at least one) |
Returns
| Field | Type | Description |
|---|---|---|
passed | boolean | true if score โฅ threshold AND keywords matched |
score | number | Jaccard similarity (0โ1) |
hasKeywords | boolean | Whether at least one required keyword was found |
gifCaptcha.validateAnswer(
"the cat fell off the table",
"the cat fell off the table unexpectedly"
);
// โ { passed: true, score: 0.857, hasKeywords: true }
gifCaptcha.validateAnswer(
"I cannot view animated images",
"the cat fell off the table",
{ requiredKeywords: ["cat", "fell"] }
);
// โ { passed: false, score: 0, hasKeywords: false }
Create a structured CAPTCHA challenge object with validation.
| Param | Type | Required | Description |
|---|---|---|---|
opts.id | number | string | โ | Unique identifier |
opts.title | string | Human-readable title (defaults to "Challenge {id}") | |
opts.gifUrl | string | โ | URL of the GIF image |
opts.sourceUrl | string | Original source URL for attribution | |
opts.humanAnswer | string | โ | Expected human description |
opts.aiAnswer | string | Typical AI model response | |
opts.keywords | string[] | Keywords for validation |
const challenge = gifCaptcha.createChallenge({
id: 1,
title: "Plot Twist",
gifUrl: "https://media.tenor.com/twist.gif",
humanAnswer: "Both fired trick guns with flags",
aiAnswer: "I cannot view animated GIFs",
keywords: ["trick", "guns", "flags"]
});
Pick N random challenges from a pool without replacement, using Fisher-Yates shuffle. Does not modify the original array.
| Param | Type | Description |
|---|---|---|
pool | Challenge[] | Array of challenge objects |
count | number | Number to pick (default: 5, max: pool length) |
const selected = gifCaptcha.pickChallenges(allChallenges, 5);
// โ 5 random challenges from the pool
Install the roundRect polyfill on CanvasRenderingContext2D. No-op if already available or outside a browser. Used by analysis and simulator chart renderers.
gifCaptcha.installRoundRectPolyfill();
// Canvas roundRect() is now available in older browsers
| Name | Value | Description |
|---|---|---|
GIF_MAX_RETRIES | 2 | Maximum retry attempts for failed GIF loads |
GIF_RETRY_DELAY_MS | 1500 | Delay between retry attempts (ms) |
GitHub ยท npm ยท Case Study ยท MIT License