Skip to content

Instantly share code, notes, and snippets.

@kentbrew kentbrew/bpsh.md
Created Mar 4, 2019

Embed
What would you like to do?
Hiding Ads from All Facebook Advertisers who have Added You From a Contact List

Hiding Ads from All Facebook Advertisers who have Added You From a Contact List

Here's a scary page:

https://www.facebook.com/ads/preferences/?entry_product=ad_settings_screen

Open up the Advertisers section and check out that first section: advertisers who use a contact list added to Facebook. Unlike the other tabs in this section, these ads have nothing to do with your behavior on Facebook or elsewhere on the Internet. All these advertisers got your name the old-fashioned way: by trading something of value for a list containing your contact information.

Per Facebook's vague-but-cheerful explainer, this is "typically" your e-mail address or phone number, but there's really no way to know for sure.

Hover over that first advertiser and you will discover an X button. Mouse over it and observe: it says "Remove." Click it and you'll see a reassuring note that says "You hid all ads from this advertiser."

Cool! One down, eleven to go. Clickety clickety click ... oh, but wait: at the bottom there's a tiny gray See More. Click it, and ... arrgh. Twelve more advertisers appear, with no idea how many more there are.

Slide down, find the tiny gray See More link, click it. Slide down, find the tiny gray See More link, click it.

Side note: wow, this inventory is garbage. The Australian Labor Party. The occasional out-of-band grocery store or hopeful e-commerce startup. Lots of out-of-state real estate and car dealerships. I am not exaggerating when I say: this stuff is even worse than the junk on TV these days. I will never ever buy anything from any of these advertisers.

It'd be great if I could turn all of these off at once, or at least see more than twelve out of ... wow, how many? No idea.

Break out a console window, a text editor, and a Web inspector.

First thing to look at is the Network tab; maybe I can see the data source they're hitting and ask for more than 12 records?

Nope. That's odd. Back to the page. Click See More, flip back to Network tab ... and the only new network requests I see are for the images.

That's ... weird. Where's the new data coming from, then?

Reload the page and sort all network requests by size. Oh, hey, here's a big one that isn't an image and doesn't match the page URL, and the response looks like data. They are dumping all of it in one whack, on page load.

Let's see if I can get it out of the browser. Right-click the request, pick Copy, and then Copy as cURL.

Paste it into a console window, add -o fb.txt to save it to a local file, and run:

curl 'https://www.facebook.com/ads/profile/advertisers/' -o fb.txt -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:65.0) Gecko/20100101 Firefox/65.0' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Referer: https://www.facebook.com/ads/preferences/?entry_product=ad_settings_screen' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Connection: keep-alive' -H 'Cookie: [my cookie here]' -H 'Cache-Control: max-age=0' -H 'TE: Trailers' --data '[custom header here]'

cURL crunches for a bit; shortly I have fb.txt on my desktop.

First thing to notice: it's quite large, confirming the suspicion that clicking through and hand-disabling a dozen advertisers at a time isn't going to be a good use of anybody's time.

The significant bit is an object that looks like this:

{
  "payload": {
    "advertisers": {
      "contact_info": [
        {
          "source_url": "https://www.facebook.com/AmigosTexas/",
          "fbid": "284000751719202",
          "ca_type": "contact_info",
          "image_url": "https://scontent-sjc3-1.xx.fbcdn.net/v/t1.0-1/p480x480/50032039_2209571229162135_435958469242126336_n.png",
          "name": "Amigos"
        },
        {
          "source_url": "https://www.facebook.com/splenda/",
          "fbid": "106045703409",
          "ca_type": "contact_info",
          "image_url": "https://scontent-sjc3-1.xx.fbcdn.net/v/t1.0-1/p480x480/17021717_10155101825823410_5175102499536536312_n.png",
          "name": "Splenda"
        },
        {
          "source_url": "https://www.facebook.com/natgeoexpeditions/",
          "fbid": "1673004346349948",
          "ca_type": "contact_info",
          "image_url": "https://scontent-sjc3-1.xx.fbcdn.net/v/t1.0-1/p480x480/18581994_1802877920029256_1950867645025140557_n.jpg",
          "name": "National Geographic Expeditions"
        }
        ... a whole lot more like this ...
      ]
    }
  }
}

Oh, good grief. There are close to 2000 advertisers listed here. All of these agencies have either uploaded (or caused to be uploaded through a partner) my contact information. If any of these lists contain my e-mail address or phone number -- yes, Facebook knows my phone number, since in a more innocent time I was incautious enough to install their mobile application -- that's a bingo.

If I hadn't already had experience dealing with companies like Facebook I'd have two questions now:

  1. if they're loading all the data in one big steaming pile (which they are) then why are they pretending they're not? Specifically, why is there a See More button and not a scrollbar?

  2. why isn't there a single button to click to hide from all of these out-of-state car dealerships and real estate brokerages?

I know the answers, of course. Lily Tomlin said it best, talking about another monopoly: "We're the phone company. We don't care. We don't have to."

So, back to the Network tab.

Let's see what the request looks like when I hide Amigos Texas.

curl 'https://www.facebook.com/ads/preferences/advertiser_hideall/?advertiser_fbid=284000751719202&undo=false&transparency_product=ad_preferences&extra_data[advertiser_category]=contact_info&extra_data[num_category_advertisers]=1990&extra_data[num_shown_category_advertisers]=36' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:65.0) Gecko/20100101 Firefox/65.0' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Referer: https://www.facebook.com/ads/preferences/?entry_product=ad_settings_screen' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Connection: keep-alive' -H 'Cookie: [my cookie here]' -H 'TE: Trailers' --data '[custom header here]'

Interesting! Let's try replaying it with cURL but changing to Splenda's advertiser_fbid, which is 106045703409. Copy, paste, fiddle with ID, hit Enter.

Nope, getting an error:

curl: (3) [globbing] bad range in column 151

Ah, okay, character 151 contains is square bracket, which is ambiguous. I'm going to want to pass the -g parameter to turn off cURL's globbing parser, which is trying to interpret that bracket itself before sending it down the wire.

Done. No error! I get this, which is mystery output ontended to be consumed by whatever JavaScript is already lurking on the page that (theoretically) made the call:

for (;;);{"__ar":1,"payload":null,"bootloadable":{},"ixData":{},"bxData":{},"gkxData":{},"qexData":{},"lid":"6664285550393462732-0"}

Not sure what this means, but let's try reloading the page.

It worked! Splenda and Amigos are both gone. Concept proven! All I need now is some way to create and run about 1999 more cURL commands.

Yes, this is probably an ideal application for a browser extension but I have been staring at browser extensions all day every day for the last couple of weeks at work, and I want to just crush this thing with a billion-pound shithammer and be done.

So I break out Node, which runs JavaScript on the back end. Using Node I won't have to write a parser for Facebook's data output, and I'm pretty sure I can execute arbitrary shell commands, such as cURL, just as if I was running them by hand.

Some fiddling later, I have this:

// exec will allow me to run cURL
const { exec } = require('child_process');

// when we have an ID we want to scrag, do this
var doStuffWith = id => {
  console.log('Attempting to remove advertiser: ' + id);

  // a sample cURL command, featuring the mythical advertiser ID 8675309
  let curl = "curl -g 'https://www.facebook.com/ads/preferences/advertiser_hideall/?advertiser_fbid=8675309&undo=false&transparency_product=ad_preferences&extra_data[advertiser_category]=contact_info&extra_data[num_category_advertisers]=1990&extra_data[num_shown_category_advertisers]=36' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:65.0) Gecko/20100101 Firefox/65.0' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Referer: https://www.facebook.com/ads/preferences/?entry_product=ad_settings_screen' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Connection: keep-alive' -H 'Cookie: [my cookie here]' -H 'TE: Trailers' --data '[custom header here]'";
  
  // swap in the ID we want to try
  let q = curl.replace(/advertiser_fbid=\d+&undo=false/, 'advertiser_fbid=' + id + '&undo=false');
  
  // try running the cURL command
  exec (q, (err, stdout, stderr) => {
    // log whatever it is we get back
    if (err) {
      console.log(err);
      return;
    }
    console.log(`stderr: ${stderr}`);  
    console.log(`stdout: ${stdout}`);
  });
};

// our data object
let data = {
  ... here we paste in that big fat JSON object from before ...
};

// grovel through all entries
for (let i = 0; i < data.payload.advertisers.contact_info.length; i = i + 1) {
  let id = data.payload.advertisers.contact_info[i].fbid;
  doStuffWith(id);
  // only do the first ten; remove when happy it's not going to light anything on fire
  if (i > 10) {
    break;
  }
}

It works with the first ten, then the first hundred, and then it takes me a couple of tries to get through the rest of the list.

When I go to the Advertisers section now I see nine ghosts that say "you hid all ads from this advertiser," and then when I go to the More link and open the Whom You've Visited tab I see a bunch more that also say that say "you hid all ads from this advertiser."

This was a fun lazy-Sunday project; I'll leave the eventual creation of a browser extension to do this with the click of a button to the student.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.