Hacking the STLToday Paywall v2022

  • April 19, 2022

Here we are again.

STLToday, the website for my hometown newspaper the St. Louis Post Dispatch, has updated their paywall and, as is tradition, it’s time to take a look, see what they did, and offer suggestions so they can make it better. In short, let’s hack the STLToday paywall.

But first, let’s review how we got here.

In 2014, while trying to read an article I noticed that STLToday had turned on a paywall. I hacked it so I could read the article, told everyone, and then it got picked up by the St. Louis media.

In 2019 the STLToday team updated the paywall and it was still easily cracked by yours truly by a bookmarklet. I offered suggestions for improvement, but it was not taken.

Cut to 2022 and they have updated the paywall logic yet again. Did they improve it? Did they finally make something that actually prevents someone from working around it? Will they ever take my suggestions? Let’s break it down!

Here’s the good news: The 2022 version is an improvement! The bad news is that it’s still very crackable.

The 2022 version starts off strong by putting their code nice and high in the logic, they have encoded their meta tags, and if the user is to be blocked, they actually delete the content from the page rather than just hiding it with CSS styles.

The basic logic is that they setup a bunch of global variables (more on that later) and then call TNCMS.Access.checkAccess with a callback function. That function checks the response and either shows the user a soft paywall with a request to sign up, or a hard paywall that says you must signup and removes the article from the page.

Right away, there are two clear methods to get around this paywall:

  1. Get that checkAccess callback function to return the soft paywall every time.
  2. Rename the article text blocks so they aren’t deleted by the code.

But wait! Before we do that we have deal with the easy stuff first, such as hiding the annoying modal nag screens, and deciding how we will launch the code. In the previous version we used a bookmarklet because they are easy to use, but now that they are finally running the paywall logic right away, and deleting the article we have to inject our code earlier. The only way to do that is with a browser extension, which is a slight bummer as it’s more work and harder to distribute than the bookmarklet, but good for Lee Publishing for making improvements! The overlays however we unchanged and hiding them is just a matter of removing a view divs and fixing the overflow style.

Ok, let’s get in to it!

Get that checkAccess callback function to return the soft paywall every time.

What is their obsession with global variables? We may never know but I went ahead and set a couple of them to true in the hopes that we can trigger this block and force the “soft” paywall.

if(oResp.required || window.show_dimissable_registration){
	if(window.show_dimissable_registration) { 
    	sCase = 'user registration';
...

switch(sCase){
	case 'user registration':
		__tnt.log('LEE: load regwall');
		window.lee_regwall_loaded = true;
		if(window.show_dimissable_registration){
			$('#reg-wall-close-soft').show();
		} else {
			$('#reg-wall-close-hard').show();
		}

I also wrote a function that waits for their TNCMS object to appear and then overrides the checkAccess function to be one that just returns the same soft paywall response every time:

window.lee_meter_loaded = true;
window.show_dimissable_registration = true;

function defuse() {
  if(window.TNCMS && window.TNCMS.Access) {
    window.TNCMS.Access.checkAccess = function(fnSuccess, fnFailure) {
      fnSuccess({required: false});
    }
  } else {
    setTimeout(defuse, 10);
  }
}

defuse();

That seems to do the trick and then you actually don’t need the #2 solution at all…but let’s review it anyway.

Rename the article text blocks so they aren’t deleted by the code.

Later on in their logic, when the “hard” paywall is drawn the following happens:

$("#asset-content .lee-article-text:not('.first-p')").html('');
$("#asset-content .inline-asset").html('');
$("#asset-content .lee-article-text.first-p").append('<p><strong>Please subscribe to continue reading&hellip;</strong></p>');

What that is doing is grabbing every paragraph of article text, except the first paragraph, and setting it to blank. If you could get your code to run first you could easily drop this by just renaming the .lee-article-text paragraphs to something different, like…hmmm, I don’t know…maybe .free-article-text!

function evade() {
  let oldClass = "lee-article-text";
  let newClass = "free-article-text";

  var divs = document.querySelectorAll('.lee-article-text');
  if(divs.length > 0) {
    for(i = 0; i < divs.length; ++i) {
      divs[i].classList.add(newClass);
      divs[i].classList.remove(oldClass);
    }
  } else {
    setTimeout(evade, 10);
  }
}

…and there you have it.

So, let’s review.

What they did right:

  1. Made sure the paywall code started faster.
  2. They removed the content rather than just hiding it.
  3. They obscured their metatags.

What they did wrong:

  1. They still send the content to the browser by default and then delete it later.
  2. They could have worked a little harder on identifying which content blocks to delete.

This is the biggest step forward we’ve seen from the STLToday paywall. Will it stop anyone with knowledge of javascript and 30 minutes of free time it takes to create a browser extension? No, but honestly, there aren’t that many of us. I commend them for at least improving it to the point where they aren’t defeated by a lowly bookmarklet any more!

You can see my full source code and quick descriptions of how to run the code on GitHub: https://github.com/mikeflynn/stltoday-paywall-buster

If you have any questions or comments, fire away on Twitter @thatmikeflynn, and go Cardinals!

Related Posts

Thoughts on Apple Bloggers and Vision Pro Coverage

I posted this on Mastodon, but I figured I would cross-post it here as well. I wonder if we’re headed for a weird place with the #Apple Blogosphere (AKA the Apple Blog Mafia). All of the main players are talking about Vision Pro all the time and saying things like “I lose track of time in here!

Read more

The Simple Pleasures of a Mobile Office Whiteboard

I’ve built a lot of stuff for my home office over the last few years of working from home, but my current favorite is something so simple: A custom rolling whiteboard A couple of weeks ago I gave myself a Saturday challenge to take my existing old whiteboard and build a rolling stand for it only with materials I had in my workshop.

Read more

I Made Myself a JARVIS Over the Weekend

With some spare parts, a USB speakerphone, and my Home Assistant server, I was able to make a competent JARVIS for my home office over the weekend…and the exciting part is that it’s only going to keep getting better! Last year was the “Year of Voice” for Home Assistant, the open source home automation platform, and the team accomplished a ton of work that enables Home Assistant users to make their own voice assistants.

Read more