Migrate from Wraith
Wraith is the BBC's Ruby screenshot-comparison tool — capture URLs across widths, diff the pixels with ImageMagick, publish a gallery.
Wraith is archived
The Wraith repository has been archived / read-only since January 2026, and its last release (v4.2.4) was June 2019. Its default capture engines — PhantomJS, CasperJS, SlimerJS — are themselves abandoned, which makes a clean install increasingly fragile. It needs replacing, not patching.
Why Dungbeetle
| Wraith | Dungbeetle | |
|---|---|---|
| Maintained | No — archived Jan 2026 | Yes |
| Engine | PhantomJS / SlimerJS / Selenium (Ruby + ImageMagick) | Playwright/Chromium (Node) |
| Diff | Pixel (ImageMagick) | Structured tree (+ tolerant pixel fallback) |
| Baselines | shots/ PNGs; wraith history | dungbeetle.snapshots/, versioned in cloud |
| Review UI | No — static gallery.html | Yes — self-host or managed |
| Runtime | Ruby + ImageMagick + PhantomJS | Node 22+ |
Two capture models — pick the baseline one
Wraith has two modes; map them deliberately:
- History mode (
wraith history→wraith latest) is the baseline model and maps cleanly onto Dungbeetle:wraith history≈dungbeetle update,wraith latest≈dungbeetle test. - Two-domain compare (capturing
englishvsliveevery run, no stored baseline) is an environment diff, not regression-vs-baseline. In Dungbeetle you'd capture one environment as the committed baseline and compare the other against it withdungbeetle test— or run two targets and compare reports. Most teams actually want the baseline model; this is a good moment to switch to it.
Translate your config
Wraith uses YAML under configs/. Paths × widths become Dungbeetle web targets:
# configs/capture.yaml
browser: "phantomjs"
domains:
live: "https://example.com"
paths:
home: /
news: /news
screen_widths:
- 320
- 1280
threshold: 5
directory: 'shots'// dungbeetle.config.json
{
"version": 1,
"project": { "name": "example" },
"lifecycle": {
"capture": [
{ "kind": "web", "name": "home-320", "driver": "playwright", "url": "https://example.com/", "screenshot": true, "viewport": { "width": 320, "height": 720 } },
{ "kind": "web", "name": "home-1280", "driver": "playwright", "url": "https://example.com/", "screenshot": true, "viewport": { "width": 1280, "height": 720 } },
{ "kind": "web", "name": "news-320", "driver": "playwright", "url": "https://example.com/news", "screenshot": true, "viewport": { "width": 320, "height": 720 } },
{ "kind": "web", "name": "news-1280", "driver": "playwright", "url": "https://example.com/news", "screenshot": true, "viewport": { "width": 1280, "height": 720 } }
]
},
"comparison": { "pixelTolerance": { "maxChangedRatio": 0.05 } }
}Field mapping:
| Wraith | Dungbeetle |
|---|---|
domains + paths | one web target per URL |
screen_widths | capture[].viewport.width (one target per width) |
browser | driver: "playwright" + browser.channel |
threshold (% changed) | comparison.pixelTolerance.maxChangedRatio (ratio, so 5% → 0.05) |
fuzz (anti-alias tolerance) | covered by pixelTolerance; or drop pixels and rely on the structured DOM diff |
directory / history_dir | dungbeetle.snapshots/ (the baselines dir) |
Consider dropping pixels entirely
Wraith is pixel-only. If your pages render server-side HTML, Dungbeetle's default structured DOM capture (no screenshot, no browser) is far less flaky than ImageMagick pixel diffs — try a target without driver/screenshot first and only add screenshots where you truly need pixels.
Re-baseline, then CI
dungbeetle update # ≈ wraith history → dungbeetle.snapshots/
dungbeetle test # ≈ wraith latest
dungbeetle ci --json report.json --html report.html # in CICommit dungbeetle.snapshots/. The old shots/ PNGs don't carry over.
Replace gallery.html with real review
Wraith's output is a static gallery you publish as an artifact. Push to a Dungbeetle cloud server instead for hosted baselines, a review/approve/promote UI, history, and flakiness analytics:
dungbeetle push --report report.json \
--server "$DUNGBEETLE_SERVER_URL" \
--client-id "$DUNGBEETLE_CLIENT_ID" --client-secret "$DUNGBEETLE_CLIENT_SECRET"