Self-hosted service
wasi-master/13ft avatar
wasi-master/13ft

13ft: a self-hosted GoogleBot impersonator for paywalled articles

My own custom 12ft.io replacement

4,281 stars226 forksPythonMIT

At a glance

What is it?
13ft is a small Flask server that fetches a paywalled page while pretending to be Google's crawler, then serves the result back to you. It is easy to run, but it is a single trick with real limits.
Who is it for?
Adopt 13ft if you want a private, MIT-licensed Flask service for reading the occasional paywalled article and you are comfortable running Docker or Python on a host you control. Do not adopt it if you need a maintained bypass for hard paywalls, if you cannot accept that the trick fails whenever a publisher serves Googlebot the same wall as everyone else, or if you plan to expose it to the open internet without a reverse proxy and TLS.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 60 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem 13ft solves, and for whom

Publishers often serve a full article to search engine crawlers so the text can be indexed, while showing a truncated version or a subscribe prompt to a normal browser. 13ft exists to exploit that gap. The README frames it as a self-hosted alternative to 12ft.io that also works on sites where 12ft.io does not, and the stated audience is someone who wants to read one article and move on. The README is explicit that it does not want to replace paying creators: it says you should support the people whose work you benefit from, and presents the tool as a way to see a single page. That framing matters, because the project is not a general content extraction library or a scraping framework. It is a single-purpose web front end for one reading scenario, and the feature set is sized accordingly.

How the GoogleBot impersonation actually works

The mechanism is a user agent swap plus a fetch. According to the README, the server pretends to be GoogleBot, Google's web crawler, and retrieves the same content Google would receive. Because publishers want their articles indexed, the crawler response typically contains the whole page rather than the metered version. 13ft then renders that response in your browser. The README also describes a loading or status page shown while the target article is being fetched, and multi-source fallbacks: if the primary approach fails, the server automatically tries other bypass methods. That fallback behaviour was contributed by a named user and is presented as an improvement for sites with stronger blocking. What the README does not describe is the internal list of fallback sources, the retry logic, or any caching layer. Those details are not in the supplied material, so treat the fallback as a black box until you read the source.

Running it: Docker, portable.py, gunicorn, and the port you expose

The shortest path is Docker. Clone the repository, change into it, and run docker compose up. Prebuilt images are also published to DockerHub and ghcr.io, so docker pull wasimaster/13ft works if you prefer not to build. The README notes that both docker and Docker Compose are required, with Compose available as the docker compose subcommand. For a plain Python install, go into the app directory, run python -m pip install -r requirements.txt, then run python portable.py. The README suggests retrying with py, python3, or py3 if the first interpreter name fails. A gunicorn path is documented as python -m gunicorn 'portable:app'. For a fixed bind address, the README gives a venv workflow with FLASK_APP=app/portable.py flask run --host=127.0.0.1 --port=9982. Two environment variables appear in the material: LOCALE, which selects a UI language, and APP_PATH, used in the systemd unit to point at the install directory. The systemd example runs flask on 127.0.0.1:22113 as user www-data, and the Apache reverse proxy example terminates TLS on port 22114 and proxies to that local port. If you follow the README's bookmarklet, note that its example points at https://localhost:5000/, which is not the port used in the systemd or venv examples, so you will need to edit it to match your deployment.

The failure mode the README admits to

The whole design rests on one assumption: that the publisher serves Googlebot a more complete page than it serves you. When that assumption breaks, 13ft has nothing left. Publishers that detect crawler user agents, that gate content by IP range or by verified crawler identity, or that simply serve the same metered page to everyone will defeat the primary method. The multi-source fallbacks exist precisely because this happens often enough to be worth engineering around, but the README does not claim they always succeed, and it does not list which sites or which fallback sources are involved. There is also a practical cost the README does not discuss: every request is a live fetch of a third-party page through your server, so latency is whatever the target site's response time is, and the loading page exists because that wait is visible. If you need reliable access to a specific publication, this is the wrong tool. A subscription or an institutional login is the mechanism that actually works there.

Where 13ft sits next to 12ft.io and Readability-style extractors

The natural comparison is 12ft.io, which the README names directly. The difference is deployment, not technique: 12ft.io is a hosted service you do not control, while 13ft is a Flask app you run yourself, which means the request to the publisher originates from your server rather than from a shared public one. That changes the failure profile. A shared public bypass service is a single point of blocking, and when a publisher blocks it, every user loses access at once; a self-hosted instance is blocked or not blocked on its own, and you can move it to a different host. The other comparison is with readability-style extraction libraries, which parse a page you already have and strip it down to article text. Those do not help with a paywall at all, because the full text never reached your client. 13ft is upstream of that problem: it tries to obtain the unmetered HTML first. If you already have the HTML, 13ft adds nothing.

Localisation, packaging, and what maintenance looks like

The UI strings are localised through the LOCALE environment variable, and locale files live in app/locales/<locale>.json. Built-in locales are en, de, fr, and ko, with en as the default. Adding a language means copying app/locales/en.json to a new file such as app/locales/es.json and translating the values, so the translation cost is bounded by the number of strings in that file. On the packaging side, the repository ships a Docker Compose file, a DockerHub image, a ghcr.io image, and a GitHub Actions build workflow whose badge appears in the README. The release history shows v0.4.0 and v0.4.1 in 2026, following v0.3.4 in late 2024, which suggests the project is still receiving changes but not on a fixed cadence. The licence is MIT, which permits commercial use, modification, and redistribution provided the copyright notice and permission notice are included. That is a permissive arrangement, but it also means no warranty and no obligation on the author to fix anything. If you depend on 13ft, you are depending on a small self-hosted tool, not a supported product, and you should be prepared to read the source when a target site changes its behaviour.

Who should run 13ft, and what to check first

Run it if you want a private instance you control, you are comfortable with Docker Compose or a Python virtualenv, and your use case is occasional reading rather than bulk access. The MIT licence and the small surface area make it easy to fork if a specific site needs a tweak. Do not run it as a public service without thinking about the reverse proxy example in the README: the Apache snippet terminates TLS, sets Strict-Transport-Security, and disables SSLv3 and TLSv1.0 and TLSv1.1, which is the minimum you would want before exposing it. Do not expect it to defeat a hard paywall that already treats crawlers and humans identically. Before you commit, test your actual target URLs against your own instance rather than trusting the general claim, and confirm which port your deployment uses, because the README's examples disagree with each other (9982 for the venv run, 22113 for systemd, 5000 in the bookmarklet, 22114 for the proxy).

Editorial conclusion

Adopt 13ft if you want a private, MIT-licensed Flask service for reading the occasional paywalled article and you are comfortable running Docker or Python on a host you control. Do not adopt it if you need a maintained bypass for hard paywalls, if you cannot accept that the trick fails whenever a publisher serves Googlebot the same wall as everyone else, or if you plan to expose it to the open internet without a reverse proxy and TLS. Before committing, verify three things on your own target sites: that the Googlebot user agent still returns the article body, that the multi-source fallback actually resolves for those domains, and that your chosen deployment path (Docker Compose, portable.py, or gunicorn) matches the port and host you intend to expose.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. wasi-master/13ft on GitHub
Community notes

Community notes