# Digital Signatures Comparison: Documenso vs DocuSeal

**Context:** Self-hosted document signing for a debt recovery portal. Needs REST API, webhooks, multi-party signing, embedding in web portal, Docker-based self-hosting.

**Date researched:** July 7, 2026

---

## Community & Project Health

| Metric | Documenso | DocuSeal |
|---|---|---|
| GitHub Stars | 13,664 | **17,469** |
| GitHub Forks | 2,868 | 1,694 |
| Contributors | **~181** | ~6 |
| Open Issues | 211 | 121 |
| Total Releases | 52 | **160** |
| Latest Release | v2.14.0 (Jun 28) | v3.1.3 (Jul 6) |
| Docker Pulls | ~505K | **~1.74M** |
| Image Size | ~690 MB | **~227 MB** |
| License | AGPL-3.0 | AGPL-3.0 + Additional Terms |
| Language | TypeScript (Next.js) | Ruby (Rails) |

## Self-Hosting Requirements (Docker on Debian)

| Aspect | Documenso | DocuSeal |
|---|---|---|
| Docker command | Multi-step, external DB required | **Single command: `docker run -p 3000:3000 -v.:/data docuseal/docuseal`** |
| Database | PostgreSQL 14+ only (mandatory) | **SQLite by default** + PostgreSQL/MySQL optional |
| Deploy time estimate | 30-60 min | 5-15 min |
| Signing certificate | Must generate manually — signing fails without one | Handled automatically |
| Docker Compose in repo | 404 — must construct from docs | **Full docker-compose.yml** with Caddy TLS |
| Updates | Manual pull + run migrations | Auto DB migration on boot |

## API Quality

| Aspect | Documenso | DocuSeal |
|---|---|---|
| Auth header | `Authorization: api_xx...xxx` | `X-Auth-Token: ***` |
| API Reference | OpenAPI at openapi.documenso.com | OpenAPI + Postman collection |
| Webhooks | Document events | Document events with auto-retry (48h, exponential backoff) |
| Official SDKs | None | **React, Vue, Angular, vanilla JS** embedding SDKs |
| API versioning | v2 (explicit) | Rolling releases |

## Feature Comparison

| Feature | Documenso | DocuSeal |
|---|---|---|
| Multi-party signing | ✅ | ✅ |
| Templates | ✅ | ✅ (PDF/DOCX field tags + HTML API) |
| Audit trail | ✅ X.509 signed | ✅ |
| White-label/branding | Paid tier | Pro tier |
| WYSIWYG form builder | ✅ | ✅ (12 field types) |
| Bulk send (CSV/XLSX) | ❌ | ✅ |
| Conditional fields | ❌ | ✅ (Pro) |
| Formulas | ❌ | ✅ (Pro) |
| SMS verification | ❌ | ✅ (Pro) |
| SSO/SAML | Enterprise | Pro |
| Embedded signing | ✅ (white-label paid) | ✅ (React, Vue, Angular, JS — free SDKs) |
| API document pricing | Unlimited (self-hosted) | $0.20/doc via API (Pro) |
| Multi-language | ✅ (i18n with Lingui) | ✅ (7 UI, 14 signing) |

## Pricing (Self-Hosted)

| Tier | Documenso | DocuSeal |
|---|---|---|
| Core | Free (AGPL-3.0) | Free (AGPL-3.0) |
| Pro | ~$300-480/yr, 5 users, $8/mo extra | $20/user/month, API key included |
| Enterprise | ~$3,000/yr — SSO, white-label, support | Custom pricing |
| API documents (Pro) | Unlimited | $0.20/document via API |
| Cloud SaaS | Free (5 docs/mo), Pro $25/mo, Team $40/mo, Enterprise $250/mo | Free tier, Pro $20/user/mo |

## Legal Compliance

| Regulation | Documenso | DocuSeal |
|---|---|---|
| ESIGN Act (US) | ✅ Dedicated page | ✅ Mentioned |
| UETA (US) | ✅ Dedicated page | ✅ Mentioned |
| eIDAS (EU) | ✅ Simple/Advanced/Qualified | ✅ EU Qualified Signature |
| SOC 2 | ✅ Documented | ❌ Not prominently |
| 21 CFR Part 11 | ✅ Documented | ❌ Not prominently |
| GDPR | ✅ Dedicated page | ✅ Mentioned |

## Verdict

**Recommend: DocuSeal** for most portal integrations. Simpler deploy, lighter, richer features, free embedding SDKs. Documenso only if SOC 2 / CFR 21 compliance docs are a hard requirement.

## Data Sources

- GitHub API: `/repos/{owner}/{repo}` — stars, forks, open issues, license, language, topics
- GitHub API: `/repos/{owner}/{repo}/contributors?per_page=1&anon=true` (Link header for total page count)
- Docker Hub API: `/v2/repositories/{owner}/{image}/` — pull count, star count, last updated
- Docker Hub API: `/v2/repositories/{owner}/{image}/tags?page_size=3` — image sizes, architectures
- Pricing pages: scraped HTML, extracted via `grep -oP` patterns
- Doc sites: Next.js SPA docs extracted from inline script payloads (`self.__next_f.push`)
