Skip to content

Commit a0690e7

Browse files
committed
docs: new alternatives guide, update star count,
1 parent b414eca commit a0690e7

11 files changed

Lines changed: 395 additions & 55 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Cap is a lightweight, modern open-source CAPTCHA alternative using <a href="http
1010

1111
## What is Cap?
1212

13-
Cap replaces visual captchas with modern, accessible and privacy-preserving <a href="https://trycap.dev/guide/effectiveness.html">proof-of-work challenges</a>. No images, no tracking, no dependencies, works everywhere.
13+
Cap replaces visual captchas with modern, accessible and privacy-preserving <a href="https://trycap.dev/guide/effectiveness.html">proof-of-work</a> and instrumentation challenges. No images, no tracking, no dependencies, works everywhere.
1414

1515
You can either run it on any JavaScript runtime, or use the standalone mode with Docker. [Learn more about how Cap works](https://trycap.dev/guide/?utm_source=github&utm_campaign=learn_more)
1616

docs/.vitepress/config.mjs

Lines changed: 65 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -199,49 +199,71 @@ export default withMermaid({
199199
{ text: "GitHub", link: "https://github.com/tiagozip/cap" },
200200
],
201201

202-
sidebar: [
203-
{ text: "Quickstart", link: "/guide/index.md" },
204-
{ text: "Feature comparison", link: "/guide/alternatives.md" },
205-
{
206-
text: "Standalone",
207-
collapsed: false,
208-
items: [
209-
{ text: "Quickstart", link: "/guide/standalone/index.md" },
210-
{ text: "API", link: "/guide/standalone/api.md" },
211-
{ text: "Options", link: "/guide/standalone/options.md" },
212-
],
213-
},
214-
{
215-
text: "Widget",
216-
collapsed: false,
217-
items: [
218-
{ text: "Usage", link: "/guide/widget.md" },
219-
{ text: "Programmatic mode", link: "/guide/programmatic.md" },
220-
{ text: "Floating mode", link: "/guide/floating.md" },
221-
],
222-
},
223-
{
224-
text: "Libraries",
225-
collapsed: true,
226-
items: [
227-
{ text: "Server", link: "/guide/server.md" },
228-
{ text: "M2M", link: "/guide/solver.md" },
229-
{ text: "Community libraries", link: "/guide/community.md" },
230-
],
231-
},
232-
{
233-
text: "Details",
234-
collapsed: true,
235-
items: [
236-
{ text: "Effectiveness", link: "/guide/effectiveness.md" },
237-
{ text: "Instrumentation", link: "/guide/instrumentation.md" },
238-
{ text: "How does Cap work?", link: "/guide/workings.md" },
239-
],
240-
},
241-
{ text: "Benchmark", link: "/guide/benchmark.md" },
242-
{ text: "Demo", link: "/guide/demo.md" },
243-
{ text: "GitHub", link: "https://github.com/tiagozip/cap" },
244-
],
202+
sidebar: {
203+
"/guide/alternatives/": [
204+
{
205+
text: "Compare Cap",
206+
items: [
207+
{ text: "← Back to docs", link: "/guide/" },
208+
{ text: "Feature comparison", link: "/guide/alternatives.md" },
209+
],
210+
},
211+
{
212+
text: "vs",
213+
items: [
214+
{ text: "reCAPTCHA", link: "/guide/alternatives/recaptcha.md" },
215+
{ text: "Turnstile", link: "/guide/alternatives/turnstile.md" },
216+
{ text: "hCaptcha", link: "/guide/alternatives/hcaptcha.md" },
217+
{ text: "Altcha", link: "/guide/alternatives/altcha.md" },
218+
{ text: "FriendlyCaptcha", link: "/guide/alternatives/friendlycaptcha.md" },
219+
{ text: "Anubis", link: "/guide/alternatives/anubis.md" },
220+
],
221+
},
222+
],
223+
"/": [
224+
{ text: "Quickstart", link: "/guide/index.md" },
225+
{ text: "Feature comparison", link: "/guide/alternatives.md" },
226+
{
227+
text: "Standalone",
228+
collapsed: false,
229+
items: [
230+
{ text: "Quickstart", link: "/guide/standalone/index.md" },
231+
{ text: "API", link: "/guide/standalone/api.md" },
232+
{ text: "Options", link: "/guide/standalone/options.md" },
233+
],
234+
},
235+
{
236+
text: "Widget",
237+
collapsed: false,
238+
items: [
239+
{ text: "Usage", link: "/guide/widget.md" },
240+
{ text: "Programmatic mode", link: "/guide/programmatic.md" },
241+
{ text: "Floating mode", link: "/guide/floating.md" },
242+
],
243+
},
244+
{
245+
text: "Libraries",
246+
collapsed: true,
247+
items: [
248+
{ text: "Server", link: "/guide/server.md" },
249+
{ text: "M2M", link: "/guide/solver.md" },
250+
{ text: "Community libraries", link: "/guide/community.md" },
251+
],
252+
},
253+
{
254+
text: "Details",
255+
collapsed: true,
256+
items: [
257+
{ text: "Effectiveness", link: "/guide/effectiveness.md" },
258+
{ text: "Instrumentation", link: "/guide/instrumentation.md" },
259+
{ text: "How does Cap work?", link: "/guide/workings.md" },
260+
],
261+
},
262+
{ text: "Benchmark", link: "/guide/benchmark.md" },
263+
{ text: "Demo", link: "/guide/demo.md" },
264+
{ text: "GitHub", link: "https://github.com/tiagozip/cap" },
265+
],
266+
},
245267

246268
socialLinks: [
247269
{ icon: "github", link: "https://github.com/tiagozip/cap" },

docs/.vitepress/theme/components/HomeV2.vue

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ function initTabs() {
8888
b.classList.add("active");
8989
renderCode(b.dataset.tab);
9090
positionIndicator(b);
91+
try {
92+
if (typeof window !== "undefined" && typeof window.plausible === "function") {
93+
window.plausible("install_tab_click", { props: { tab: b.dataset.tab } });
94+
}
95+
} catch {}
9196
};
9297
b.addEventListener("click", handler);
9398
handlers.push([b, handler]);
@@ -109,6 +114,11 @@ function initTabs() {
109114
await navigator.clipboard.writeText(SNIPPETS[currentSnippet]);
110115
copyBtn.classList.add("copied");
111116
copyBtn.querySelector(".copy-label").textContent = "Copied";
117+
try {
118+
if (typeof window !== "undefined" && typeof window.plausible === "function") {
119+
window.plausible("install_snippet_copy", { props: { tab: currentSnippet } });
120+
}
121+
} catch {}
112122
clearTimeout(copyTimer);
113123
copyTimer = setTimeout(() => {
114124
copyBtn.classList.remove("copied");
@@ -375,12 +385,58 @@ function initLiveArchitecture() {
375385
});
376386
}
377387
388+
function track(name, props) {
389+
try {
390+
if (typeof window !== "undefined" && typeof window.plausible === "function") {
391+
window.plausible(name, props ? { props } : undefined);
392+
}
393+
} catch {}
394+
}
395+
396+
function initCtaTracking() {
397+
const handlers = [];
398+
document.querySelectorAll("#homev2 [data-cta]").forEach((el) => {
399+
const handler = () => {
400+
track("cta_click", {
401+
cta: el.getAttribute("data-cta"),
402+
location: el.getAttribute("data-cta-location") || "unknown",
403+
});
404+
};
405+
el.addEventListener("click", handler);
406+
handlers.push([el, handler]);
407+
});
408+
registerCleanup(() => handlers.forEach(([el, h]) => el.removeEventListener("click", h)));
409+
}
410+
411+
async function loadGithubStars() {
412+
const el = document.getElementById("homev2-gh-stars");
413+
if (!el) return;
414+
try {
415+
const cached = sessionStorage.getItem("cap-gh-stars");
416+
if (cached) {
417+
el.textContent = cached;
418+
}
419+
const res = await fetch("https://api.github.com/repos/tiagozip/cap", {
420+
headers: { Accept: "application/vnd.github+json" },
421+
});
422+
if (!res.ok) return;
423+
const data = await res.json();
424+
const n = data.stargazers_count;
425+
if (typeof n !== "number") return;
426+
const formatted = n >= 1000 ? `${(n / 1000).toFixed(1)}k` : `${n}`;
427+
el.textContent = formatted;
428+
sessionStorage.setItem("cap-gh-stars", formatted);
429+
} catch {}
430+
}
431+
378432
onMounted(() => {
379433
document.documentElement.classList.add("home-v2-active");
380434
initTabs();
381435
loadStats();
382436
initCountUp();
383437
initLiveArchitecture();
438+
initCtaTracking();
439+
loadGithubStars();
384440
});
385441
386442
onBeforeUnmount(() => {
@@ -404,12 +460,14 @@ onBeforeUnmount(() => {
404460
<VPNavBarSearch class="homev2-search" />
405461
</div>
406462
<nav>
407-
<a href="/guide/">Docs</a>
408-
<a href="#features">Features</a>
463+
<a href="/guide/" data-cta="docs" data-cta-location="nav">Docs</a>
464+
<a href="#features" data-cta="features" data-cta-location="nav">Features</a>
409465
<a
410466
class="gh-link"
411467
href="https://github.com/tiagozip/cap"
412468
aria-label="GitHub"
469+
data-cta="github"
470+
data-cta-location="nav"
413471
>
414472
<svg
415473
viewBox="0 0 24 24"
@@ -422,7 +480,7 @@ onBeforeUnmount(() => {
422480
d="M12 .5C5.73.5.5 5.73.5 12c0 5.08 3.29 9.39 7.86 10.91.58.1.79-.25.79-.56 0-.28-.01-1.02-.02-2-3.2.69-3.87-1.54-3.87-1.54-.52-1.32-1.27-1.67-1.27-1.67-1.04-.71.08-.7.08-.7 1.15.08 1.76 1.18 1.76 1.18 1.02 1.75 2.68 1.24 3.34.95.1-.74.4-1.24.72-1.53-2.55-.29-5.24-1.28-5.24-5.68 0-1.25.45-2.28 1.18-3.08-.12-.29-.51-1.46.11-3.04 0 0 .96-.31 3.15 1.18.91-.25 1.89-.38 2.86-.38.97 0 1.95.13 2.86.38 2.19-1.49 3.15-1.18 3.15-1.18.62 1.58.23 2.75.11 3.04.73.8 1.18 1.83 1.18 3.08 0 4.41-2.69 5.38-5.25 5.67.41.35.78 1.05.78 2.11 0 1.52-.01 2.75-.01 3.12 0 .31.21.67.8.56C20.71 21.38 24 17.08 24 12c0-6.27-5.23-11.5-11.5-11.5z"
423481
/>
424482
</svg>
425-
<span>5.2k</span>
483+
<span id="homev2-gh-stars">6.2k</span>
426484
</a>
427485
</nav>
428486
</div>
@@ -442,9 +500,9 @@ onBeforeUnmount(() => {
442500
</p>
443501
444502
<div class="actions">
445-
<a class="btn primary" href="/guide/">Read the docs <span class="arr"></span></a>
446-
<a class="btn" href="/guide/demo.html">Demo <span class="arr"></span></a>
447-
<a class="btn" href="https://github.com/tiagozip/cap">GitHub</a>
503+
<a class="btn primary" href="/guide/" data-cta="docs" data-cta-location="hero">Read the docs <span class="arr"></span></a>
504+
<a class="btn" href="/guide/demo.html" data-cta="demo" data-cta-location="hero">Demo <span class="arr"></span></a>
505+
<a class="btn" href="https://github.com/tiagozip/cap" data-cta="github" data-cta-location="hero">GitHub</a>
448506
</div>
449507
</div>
450508
@@ -472,7 +530,7 @@ onBeforeUnmount(() => {
472530
473531
<div class="wrap">
474532
<div class="trust">
475-
<span class="trust-item">5k stars on GitHub</span><span class="trust-sep">·</span>
533+
<span class="trust-item">6k stars on GitHub</span><span class="trust-sep">·</span>
476534
<span class="trust-item">Apache 2.0</span>
477535
<span class="trust-sep">·</span>
478536
<span class="trust-item">Zero dependencies</span>
@@ -886,9 +944,9 @@ onBeforeUnmount(() => {
886944
your users' traffic.
887945
</p>
888946
<div class="actions">
889-
<a class="btn primary" href="/guide/">Read the docs <span class="arr">→</span></a>
890-
<a class="btn" href="/guide/demo.html">Try the demo <span class="arr">↗</span></a>
891-
<a class="btn" href="https://github.com/tiagozip/cap">Star on GitHub</a>
947+
<a class="btn primary" href="/guide/" data-cta="docs" data-cta-location="cta_block">Read the docs <span class="arr">→</span></a>
948+
<a class="btn" href="/guide/demo.html" data-cta="demo" data-cta-location="cta_block">Try the demo <span class="arr">↗</span></a>
949+
<a class="btn" href="https://github.com/tiagozip/cap" data-cta="github" data-cta-location="cta_block">Star on GitHub</a>
892950
</div>
893951
</div>
894952
</div>

docs/guide/alternatives.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,29 +26,39 @@ Cloudflare Turnstile is a great alternative to Cap, but unfortunately, it is kno
2626

2727
Additionally, unlike Turnstile, Cap is open-source and self-hosted. With Turnstile, if Cloudflare's algorithm marks a user as "suspicious," you cannot override it. Cap puts the levers of control in your hands, so you decide the difficulty and strictness, not a third party.
2828

29+
[Full comparison: Cap vs Cloudflare Turnstile →](./alternatives/turnstile.md)
30+
2931
### reCAPTCHA
3032

3133
Not only is Cap significantly smaller and faster than reCAPTCHA, it's open-source, fully free, and much more private. Cap doesn't require you to check traffic signs or solve puzzles, and it doesn't track users or collect data.
3234

3335
reCAPTCHA v2 ("I'm not a robot") is getting harder for humans while remaining trivial for AI solvers (especially audio challenges). v3 (Invisible) is great, but if Google thinks you are "suspicious" (e.g., using a VPN or privacy tools), it often blocks you entirely or forces a hard puzzle loop with no way out.
3436

37+
[Full comparison: Cap vs reCAPTCHA →](./alternatives/recaptcha.md)
38+
3539
### hCAPTCHA
3640

3741
Pretty much the same as reCAPTCHA, however, while it's significantly more resistant to bots, it imposes a heavy "Puzzle Tax" on your users.
3842

3943
Users hate puzzles. They leave. Drop-off rates on hCaptcha challenges can be **5-15%** depending on difficulty. Additionally, hCaptcha's free tier is aggressive with serving puzzles to save their own costs, which hurts your conversion rates.
4044

45+
[Full comparison: Cap vs hCaptcha →](./alternatives/hcaptcha.md)
46+
4147
### Altcha
4248

4349
Cap is slightly smaller than Altcha and includes extra features like progress tracking, instrumentation challenges, and a simpler dashboard. If you don't need these, Altcha is still a solid choice.
4450

51+
[Full comparison: Cap vs Altcha →](./alternatives/altcha.md)
52+
4553
### mCAPTCHA
4654

4755
While mCAPTCHA is similar to both Cap and Altcha, it seems to have been deprecated and has a significantly larger widget bundle.
4856

4957
### FriendlyCaptcha
5058

51-
Unlike FriendlyCaptcha, Cap is completely free and self-hosted (FriendlyCaptcha is €39/month for only 5k requests and 5 domains).
59+
Unlike FriendlyCaptcha, Cap is completely free and self-hosted at any volume (FriendlyCaptcha's Starter plan is €9/month for 1,000 requests/month, with higher tiers as you scale).
60+
61+
[Full comparison: Cap vs FriendlyCaptcha →](./alternatives/friendlycaptcha.md)
5262

5363
### MTCaptcha
5464

@@ -69,3 +79,5 @@ They also only operate in the US, Canada, Argentina, India, Israel and a small s
6979
While Anubis is a great scraper deterrent and uses the same proof-of-work concept as Cap, it uses a low difficulty by default (which is easier for bots to solve) and does not provide a standalone CAPTCHA server.
7080

7181
Cap also implements dynamic instrumentation challenges, which make it harder for bots to finish the process after solving PoW.
82+
83+
[Full comparison: Cap vs Anubis →](./alternatives/anubis.md)

docs/guide/alternatives/altcha.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
title: Cap vs Altcha
3+
description: How Cap compares to Altcha. Both are open-source proof-of-work CAPTCHAs — here's where they differ.
4+
---
5+
6+
# Cap vs Altcha
7+
8+
Altcha is the closest project in spirit to Cap: open-source, proof-of-work, no fingerprinting, no third-party dependency. Both are good choices. The differences come down to features and operational shape.
9+
10+
Altcha also has a commercial product called **Altcha Sentinel** that layers ML-based threat detection on top of the open-source widget. The comparison below is mostly between Cap and the open-source Altcha widget; if you're considering Sentinel, you're comparing a paid SaaS to a self-hosted OSS project, which is a different decision.
11+
12+
## Quick verdict
13+
14+
If you want a minimal, library-style PoW CAPTCHA you can drop into a Node project and forget about, the open-source Altcha is great. If you want a turn-key self-hosted service with a dashboard, multi-site-key support, instrumentation challenges layered on top of PoW, and a UI that progress-tracks the solve — without paying for Sentinel — Cap is the better fit.
15+
16+
## Where Altcha makes sense
17+
18+
- You want a tiny, library-only integration with no separate service to run.
19+
- You don't need a second verification layer beyond proof-of-work, or you're willing to pay for Sentinel to get ML-based detection.
20+
- You're already integrated with Altcha and the migration cost outweighs the differences below.
21+
22+
## Where Cap is the better choice
23+
24+
- **Two independent verification layers, free.** Cap runs proof-of-work *and* dynamic JavaScript [instrumentation challenges](../instrumentation.md) in parallel, both included. Defeating one doesn't defeat the other. The open-source Altcha is PoW only; the second layer (ML-based) requires paying for Sentinel.
25+
- **Standalone server with dashboard, free.** Cap ships a one-Docker-container deployment with a web dashboard, multi-site-key management, analytics, and a reCAPTCHA-compatible siteverify endpoint. Altcha's open-source side leaves you to wire those yourself; the all-in-one experience is Sentinel-only.
26+
- **Smaller widget.** Cap is ~20 KB. Altcha is ~34 KB gzipped.
27+
- **Progress tracking.** Cap's widget reports solve progress to the user as a percentage — meaningful UX feedback during the small wait.
28+
- **Floating and programmatic modes.** Cap can hide entirely or float over a button until form submit. Altcha's display modes are simpler.
29+
- **Customizable look.** Cap exposes CSS variables for colors, size, position, and icons. Altcha's customization is more limited.
30+
31+
## Where they're similar
32+
33+
- Both are open-source (Cap is Apache-2.0, Altcha's widget is MIT) with no telemetry.
34+
- Both run client-side proof-of-work to make abuse expensive.
35+
- Both work without any third-party network round-trip when self-hosted.
36+
- Both are GDPR/CCPA-friendly by design.
37+
38+
## See also
39+
40+
- [Live demo](../demo.md) — try Cap in your browser
41+
- [How Cap detects bots](../effectiveness.md) — proof-of-work + instrumentation
42+
- [All alternatives](../alternatives.md) — full feature matrix

docs/guide/alternatives/anubis.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
title: Cap vs Anubis
3+
description: How Cap compares to Anubis, the proof-of-work scraper deterrent. When to use each.
4+
---
5+
6+
# Cap vs Anubis
7+
8+
Anubis is a proof-of-work scraper deterrent, popular in self-hosted communities for blocking AI training crawlers and aggressive scrapers at the edge. It and Cap share the proof-of-work core, but they're aimed at different problems.
9+
10+
## Quick verdict
11+
12+
Use **Anubis** when you want to gate an entire site or path against bots and scrapers at the reverse-proxy level — usually because crawlers are eating your bandwidth. Use **Cap** when you want to gate a specific *action* — a form submission, an API call, an account creation — and let normal browsing continue freely.
13+
14+
## Where Anubis makes sense
15+
16+
- You want to put a PoW wall in front of an entire site or sub-path.
17+
- The threat model is mass scraping or bot-driven request floods at the edge.
18+
- You're comfortable making every visitor solve a small challenge before any page loads.
19+
20+
## Where Cap is the better choice
21+
22+
- **Per-action protection, not per-pageview.** Cap protects forms, signups, contact pages, and API endpoints — exactly where abuse converts to cost. Visitors browse normally.
23+
- **Difficulty is per-action.** Anubis's challenge has to be small enough not to hurt every page load, which limits how high you can crank it. Cap is configured per-action, so difficulty can be set higher on signup or login forms without hurting browsing.
24+
- **Two verification layers.** Cap layers [instrumentation challenges](../instrumentation.md) on top of PoW, so even bots that bring GPU-acceleration to the proof-of-work step still have to fake a real browser environment.
25+
- **Standalone server with a dashboard.** Cap ships analytics, multi-site-key management, and a reCAPTCHA-compatible siteverify endpoint out of the box.
26+
- **Widget UX.** Cap is meant to be visible to humans on a form — there's a checkbox, progress indicator, and brand surface. Anubis is a transparent gate.
27+
28+
## They can coexist
29+
30+
If you're already running Anubis in front of a site for crawler protection, you can still use Cap on individual high-value forms and API endpoints inside that site. The two solve different problems and don't conflict.
31+
32+
## See also
33+
34+
- [Live demo](../demo.md) — try Cap in your browser
35+
- [How Cap detects bots](../effectiveness.md) — proof-of-work + instrumentation
36+
- [All alternatives](../alternatives.md) — full feature matrix

0 commit comments

Comments
 (0)