LibreCrawl now has a plugin system. Drop a single JavaScript file into web/static/plugins/, refresh the page, and it appears as a new tab in the interface with full access to every URL, link, issue, and statistic from your crawl. No backend code, no build step, no fork to maintain. This post explains how the system works and walks through building your first custom analysis tab.

Why We Built a Plugin System

Every SEO team we've talked to has at least one custom check that no crawler ships out of the box. An agency wants to flag pages missing their client's specific schema type. An in-house team wants a readability score weighted for their industry. A consultant wants to spot pages that mention a product but never link to it. These checks are rarely hard to compute. The hard part has always been getting them into the tool where the crawl data lives.

Paid crawlers handle this with custom extraction fields and export-to-spreadsheet workflows, and to be fair, tools like Screaming Frog do custom extraction well. But an extraction column is not a report. If you want a dedicated view with its own scoring, tables, and summary cards, you're waiting on the vendor's roadmap.

LibreCrawl is open source under the MIT license, so in theory you could always fork it and add whatever tab you wanted. In practice, forks rot. Every upstream release means merging conflicts in code you touched six months ago. We wanted extension to be cheap enough that you'd actually do it: one file, plain JavaScript, and nothing to rebase when we ship updates.

How It Works: One File, One Tab

The entire installation process is a file copy:

  1. Write (or download) a plugin as a single .js file
  2. Place it in web/static/plugins/ in your LibreCrawl installation
  3. Refresh the browser

That's it. The plugin shows up as a new tab alongside the built-in ones, with its own label and icon. There is zero backend code involved. You don't touch Python, you don't register routes, you don't restart the server. The crawler already collects the data during every crawl; plugins are a presentation and analysis layer that runs entirely in the browser on top of it.

This design has a useful side effect: a plugin can't break your crawls. The worst a badly written plugin can do is render an ugly tab. The crawl engine, the queue, and your data are all out of reach.

The Plugin API

A plugin announces itself by calling LibreCrawlPlugin.register() with a metadata object and its lifecycle hooks:

  • id - a unique identifier for the plugin
  • name - the display name
  • version - your version string
  • author - who wrote it
  • description - what it does
  • tab - an object with label (the tab text), icon (an emoji), and position (where the tab sits in the row)

Lifecycle Hooks

Alongside the metadata, you implement whichever of five hooks your plugin needs:

  • onLoad() - runs once when the plugin is loaded, useful for one-time setup
  • onTabActivate(container, data) - runs when the user clicks your tab; you get a DOM container to render into and the current crawl data
  • onTabDeactivate() - runs when the user switches away, so you can clean up timers or listeners
  • onDataUpdate(data) - called live while a crawl is running, every time new data arrives
  • onCrawlComplete(data) - called once when the crawl finishes

The onDataUpdate() hook deserves emphasis. Your plugin isn't limited to post-crawl reporting; it can update its analysis in real time as pages come in. A scoring plugin can show its numbers climbing while a 50,000 URL crawl is still in progress, the same way the built-in tabs update live.

What's in the Data Object

Every data-receiving hook gets the same object, and it contains essentially everything LibreCrawl knows about the crawl:

  • urls - full metadata for every crawled URL: titles, meta descriptions, headings, word counts, status codes, link counts, images, schema markup, analytics detection, and more
  • links - every discovered link with its anchor text and placement
  • issues - the SEO issues LibreCrawl detected during the crawl
  • stats - crawl-level numbers: URLs discovered, URLs crawled, depth, and speed

This is the same data that powers the built-in tables and the interactive site structure graph we shipped this week. If you've used the LibreCrawl API, the shape will feel familiar. The difference is that a plugin gets it pushed into the browser for free, with no polling and no authentication to wire up.

Your First Plugin in Under 30 Lines

Here is a complete, working plugin. It registers a tab and, when activated, renders a count of crawled pages and how many returned errors:

LibreCrawlPlugin.register({
    id: 'status-summary',
    name: 'Status Summary',
    version: '1.0.0',
    author: 'Your Name',
    description: 'Shows a quick summary of crawl status codes',
    tab: {
        label: 'Status Summary',
        icon: '📊',
        position: 10
    },
    onTabActivate(container, data) {
        const total = data.urls.length;
        const errors = data.urls.filter(u => u.status_code >= 400).length;
        container.innerHTML = `
            <div class="plugin-content">
                <div class="plugin-header">
                    <h2>Status Summary</h2>
                </div>
                <div class="stat-card">
                    ${total} pages crawled, ${errors} with error status codes
                </div>
            </div>
        `;
    }
});

Save that as status-summary.js in web/static/plugins/, refresh, and you have a new tab. That's the entire development loop: edit the file, refresh the browser, see the result. No compiler, no dev server, no dependencies.

Making Plugins Look Native

A plugin tab shouldn't look like a foreign object bolted onto the interface, so plugins can reuse LibreCrawl's built-in CSS classes directly:

  • .plugin-content and .plugin-header - the standard wrapper and header layout for plugin tabs
  • .data-table - the same table styling the built-in URL and issue tables use
  • .stat-card - the summary cards you see on the overview
  • .score-good, .score-needs-improvement, .score-poor - traffic-light score styling for anything you grade

One practical detail: give your container overflow-y: auto with a max-height of calc(100vh - 280px). That keeps long tables scrolling inside your tab instead of pushing the whole interface down the page. We learned this one the hard way while building the examples.

Plugins also get a small utility belt through this.utils:

  • showNotification(message, type) - pop a toast notification in the LibreCrawl UI
  • formatUrl(url) - display URLs the same way the rest of the interface does
  • escapeHtml(text) - escape crawled content before rendering it

That last one matters more than it looks. Your plugin renders titles, meta descriptions, and anchor text scraped from third-party websites. Run everything through escapeHtml() before it touches innerHTML, or a page with a script tag in its title becomes a script running in your browser.

A Bigger Idea: A Content Quality Scorer

The status counter shows the mechanics, but the interesting plugins do real analysis. Since every URL comes with word counts and heading data, a content quality scorer is a natural next step. The core logic fits in a screen of code:

onCrawlComplete(data) {
    this.scores = data.urls
        .filter(u => u.status_code === 200)
        .map(u => {
            let score = 0;
            if (u.word_count >= 300) score += 40;
            else if (u.word_count >= 150) score += 20;
            if (u.headings && u.headings.h1 === 1) score += 30;
            if (u.headings && u.headings.h2 >= 2) score += 30;
            const cls = score >= 70 ? 'score-good'
                : score >= 40 ? 'score-needs-improvement'
                : 'score-poor';
            return { url: u.url, score, cls };
        })
        .sort((a, b) => a.score - b.score);
    this.utils.showNotification('Content scoring complete', 'success');
}

Render the results into a .data-table with the score classes applied, sorted worst-first so thin pages surface at the top, and you have a prioritized content triage list that updates itself on every crawl. Tweak the thresholds to match your own editorial standards; that's the point of owning the code.

What Ships in the Box

LibreCrawl includes two plugins to get you started:

  • _example-plugin.js - a documented template covering the full API surface. Copy it, rename it, and start editing. The underscore prefix keeps it visually separated from real plugins in the folder.
  • e-e-a-t.js - a working E-E-A-T analyzer that examines crawled pages for experience, expertise, authoritativeness, and trust signals. It's a genuinely useful tab on its own, and it doubles as a reference for what a complete analysis plugin looks like: scoring logic, stat cards, sortable tables, live updates.

Reading e-e-a-t.js before writing your own plugin is the fastest way to learn the patterns. It exercises every hook and every utility, and it's short enough to read over coffee.

Plugin Ideas Worth Stealing

Once you see the data object, ideas come quickly. A few we'd genuinely like to see built:

  • Anchor text auditor - the links data includes anchor text and placement, so you can flag generic anchors ("click here", "read more") pointing at important pages, or spot money pages that only receive footer links
  • Schema coverage map - the urls data includes detected schema markup, so a plugin can show which page templates carry structured data and which are bare
  • Analytics gap finder - LibreCrawl detects analytics on crawled pages, and a plugin can list every page where your tracking snippet is missing
  • Title and meta rewriter queue - filter the issues data down to title and description problems, then present them as a worklist with character counts
  • Crawl velocity dashboard - the stats object updates live, so a plugin can chart discovered versus crawled URLs and crawl speed over the life of a crawl

None of these require anything beyond the data every plugin already receives. Each is an evening of work, not a project.

Sharing What You Build

A plugin system is only as good as the plugins people share, which is why we followed this release with the LibreCrawl Plugin Workshop, a central place to publish your plugins and install ones the community has built. If you write something useful, a schema validator, a hreflang checker, an internal anchor text auditor, publishing it means the next person doesn't have to write it again.

Everything here is MIT licensed, plugins included by convention. Use them commercially, modify them, ship them to clients. No permission needed.

Honest Limitations

In the spirit of transparency: plugins analyze the data LibreCrawl collects, they don't change what it collects. If your analysis needs data the crawler doesn't gather, a plugin can't conjure it, and that's a feature request for the crawler itself. Plugins are also plain JavaScript files you install yourself, so read the code of anything you download before dropping it in the folder. It runs in your browser with access to your crawl data, and a two-minute skim is cheap insurance.

Conclusion

SEO tools have always forced a choice: accept the reports the vendor built, or export to spreadsheets and rebuild your analysis by hand after every crawl. A plugin system dissolves that choice. The crawler does what crawlers do well, collecting complete data at scale, and you decide what questions to ask of it, inside the tool, updating live.

The barrier to entry is genuinely low. If you can write JavaScript that filters an array and sets innerHTML, you can ship a LibreCrawl plugin today. Start from _example-plugin.js, steal patterns from the E-E-A-T analyzer, and share the result on the Workshop.

Key takeaways:

  • Drop a single .js file into web/static/plugins/ and it becomes a new tab, zero backend code
  • Five lifecycle hooks cover load, tab activation, live crawl updates, and crawl completion
  • Plugins get full crawl data: URL metadata, links, issues, and stats
  • Built-in CSS classes and this.utils helpers make plugins look and behave native
  • Start from the included _example-plugin.js template and the E-E-A-T analyzer example

Build Your First LibreCrawl Plugin

Download LibreCrawl, copy the example plugin, and have a custom analysis tab running in minutes. Free forever, MIT licensed, no limits.

Download LibreCrawl