Skip to content
SkilledDragonEngineering Intelligence
AI DropKeylessOctober 20, 2026

Trafilatura kept 2 of 5 hidden notes from a help page. A visibility filter removes both.

We ran Trafilatura 2.3.1 on a help page with five notes a reader never sees. The extract kept the stylesheet-hidden note and the hidden-attribute note, and a small pre-filter removed both.

By David Discua

Measured in the lab

5
hidden notes on the page
2
kept by raw Trafilatura
0
kept after the filter
24/24
tests passed
Hidden notes on the page5
Trafilatura raw extractclass rule + hidden attribute2
Filtered extract0
  • 24 of 24 tests passed, 0 skipped
  • Raw extract keeps NOTA-CLASE and NOTA-HIDDEN
  • Filtered extract keeps no notes and keeps the help text
  • class="hidden" on its own passes Trafilatura's discard rule
  • No API keys, and the CLI reads local files only

From reports/gate.json · run on October 19, 2026. trafilatura 2.3.1 (v2.3.1, e2f85c965662) on CPython 3.13.16 with beautifulsoup4 4.15.0; local keyless run, GitHub Actions not run yet

How it is wired

extracttextfirstvisibleHelp page5 hidden notesvisible_htmldrops hidden textTrafilaturav2.3.1 extractYour AI2 notes arrive

01/03A help page carries five notes a reader never sees.

Trafilatura is a Python library that pulls the main text out of a web page, so if you hand its output to a model, the model reads whatever Trafilatura keeps. We ran Trafilatura 2.3.1 on a local help page with five notes a reader never sees, and two of them came through in the extract. A small visibility filter that runs before Trafilatura removed both and left the help text in place.

The catch

The page is a Spanish help article about deleting an account, with one note per hiding method. Trafilatura dropped three of them: the paragraph with an inline display:none, the HTML comment, and the JSON inside a script tag. It kept a paragraph hidden by a class rule in the page's own stylesheet (NOTA-CLASE) and one that carries the hidden attribute (NOTA-HIDDEN).

Trafilatura's discard XPath at the pinned commit decides from the element itself. It matches display:none written in a style attribute, and it matches class names and ids against a pattern such as ' hidden| hide'. It never reads the stylesheet, so a class whose only job is .solo-ia{display:none} in a <style> block looks like ordinary text. It never checks the hidden attribute either.

The class pattern has a second gap. A paragraph with class="hidden" and no other class in front of it also passes, because the pattern expects a space before hidden. On our second fixture, controles.html, the raw extract kept NOTA-CLASEHIDDEN and NOTA-CLASE.

The filter has limits of its own. It reads simple class selectors only, so descendant selectors, comma groups, attribute selectors and media queries stay in the page. White-on-white text, opacity:0, font-size:0 and off-screen text are out of scope. On controles.html the filter kept NOTA-CLASEHIDDEN, because no rule in that page's stylesheet hides the .hidden class.

What we ran (keyless)

git clone https://github.com/SkilledDragonCorp/oculto-trafilatura-estilo.git
cd oculto-trafilatura-estilo
uv sync --frozen
uv run --frozen pytest -v
uv run --frozen vis-extract fixtures/ayuda.html --raw
uv run --frozen vis-extract fixtures/ayuda.html
uv run --frozen python scripts/report.py

From reports/gate.json, run on October 19, 2026:

FieldValue
Pintrafilatura==2.3.1, tag v2.3.1, commit e2f85c96
RuntimeCPython 3.13.16, beautifulsoup4 4.15.0
Tests24 passed, 0 failed, 0 skipped, in 2.78 s
ayuda.html rawNOTA-CLASE, NOTA-HIDDEN
ayuda.html filteredno notes
controles.html rawNOTA-CLASEHIDDEN, NOTA-CLASE
controles.html filteredNOTA-CLASEHIDDEN
controles-aviso.html rawNOTA-CLASE

vis-extract fixtures/ayuda.html --raw prints the two notes and exits with code 4. Without --raw it prints a count of 0 and exits with code 0, and the test suite checks that the sentence Para borrar tu cuenta is still in the filtered text. This was a local run on Linux. One test starts a child process under unshare --net and checks that a connect to an outside address fails. The workflow also defines a gitleaks scan, pip-audit and osv-scanner, and a relocated copy of Trafilatura's own build job. GitHub Actions has not run any of them yet, so we have no CI result to report.

How it is wired

extract_raw calls trafilatura.extract on the local HTML string, the same call the upstream quickstart makes, without fetch_url. visible_html parses the page with BeautifulSoup and removes comments, script, style, template and noscript elements, anything with the hidden attribute or aria-hidden="true", inline display:none and visibility:hidden, and elements whose class the page's own <style> block marks hidden. extract_visible runs Trafilatura on what is left. The CLI reads one .html file under fixtures/ or the OS temp directory, rejects URLs, and stops at 2 MB, so nothing is fetched or sent.

Minilab (open source)

Upstream is adbar/trafilatura (6,999 stars, Apache-2.0, Python, as of October 20, 2026). The lab is MIT. Save a page of your own as .html in fixtures/, run vis-extract on it with and without --raw, and compare the two counts.

Run it yourself

SkilledDragonCorp/oculto-trafilatura-estilo

Clone, install and run the report with no API keys. The numbers above are what that run writes.

uv sync --frozen && uv run --frozen python scripts/report.py

SkilledDragon is not affiliated with Trafilatura or its authors. Numbers are from our own keyless lab run; GitHub Actions has not run these jobs yet, so re-run the report before relying on them. Marks belong to their owners.

All labs