This is the source code behind our project to collect political ads on Facebook. Built versions are available for Firefox and Chrome. You can browse the American ads we've collected at ProPublica, and the Australian ads over on the Guardian's website.
We're asking our readers to use this extension when they are browsing Facebook. While they are on Facebook a background script runs to collect ads they see. The extension shows those ads to users and asks them to decide whether or not a particular ad is political. Serverside, we use those ratings to train a naive bayes classifier that then automatically rates the other ads we've collected. The extension also asks the server for the most recent ads that the classifier thinks are political so that users can see political ads they haven't seen. We're careful to protect our user's privacy by not sending identifying information to our backend server.
We're open sourcing this project because we'd love your help. Collecting these ads is challenging, and the more eyes on the problem the better.
- Download the Facebook Political Ad Collector for Firefox
- Download the Facebook Political Ad Collector for Chrome
The extension popup is a preact application and you can build a development version by running the following:
cd extension
npm install
npm run watch
If you are a Firefox user you can open a clean browser instance with:
npm run ff
and any changes will automatically refresh the extension.
In Chrome you'll need to add an unpacked extension by following these directions.
The backend server is a rust application that runs on top of diesel and hyper. You'll need the diesel command line interface to get started and to create the database:
cargo install diesel_cli
diesel database setup
You can kick the tires by running:
cd backend/server
cargo build
cargo run
We train the classifier using python and scikit learn and the source is in backend/classifier/
. We're using pipenv to track dependencies. To get started you can run:
cd backend/classifier/
pipenv install
pipenv shell
And to build the classifier you'll want to run:
./classify build
To classify the ads you've collected you can run:
./classify classify
Translations for the extension are stored in extension/_locales/${locale}/messages.json
.
A locale
is a ISO 639-1 language code (e.g. en
, de
) with an optional ISO 3166-1 Alpha-2 country suffix (e.g. de_CH
).
Users can select from all known languages and countries while onboarding. The UI then uses the first available translation in following order: ${langauge}_${country}
, ${langauge}
, en
.
In extension/src/i18n.js
a list of active language and country codes can be defined. Active ones get prioritised in the UI.
You can customize, for example font sizes, with [lang]
and [data-locale]
CSS selectors:
[lang=de] .toggle {
font-size: 0.78rem;
}
[data-locale=de_CH] .toggle {
font-size: 0.78rem;
}
- Help Us Monitor Political Ads Online
- Mehr Transparenz im Schatten-Wahlkampf
- Bringen Sie Licht in den dunklen Facebook-Wahlkampf
- Wie werben die Parteien auf Facebook?
- So werben die Parteien auf Facebook
- Warum Zuckerberg den deutschen Wahlkampf durchleuchten ließ
- Trust Issues
- Facebook Allowed Questionable Ads in German Election Despite Warnings
- Versuch der anonymen Einflussnahme auf den Bundestagswahlkampf
- Bundestagswahl: Versuch anonymer Einflussnahme
- Same-sex marriage survey: help us track targeted ads on Facebook
- Revealed: how Australians are targeted with political advertising on Facebook (Searchable Database)
- Adani posts weird video ad on Facebook to fend off Carmichael criticism
- How Malcolm Turnbull, GetUp and Adani are using Facebook ads to push their agenda
- Hjælp os med at kortlægge politiske reklamer på Facebook
- Facebook Allowed Political Ads That Were Actually Scams and Malware
- Political Ads on Facebook
- Helfen Sie uns, verdeckte Polit-Werbung zu enttarnen
In general, the project needs more tests. We've written a couple of tests for parsing the Facebook timeline in the extension directory, and a few for the tricky bits in the server, but any help here would be great!
Also, the rust backend needs a bit of love and care, and there is a bit of a mess in backend/server/src/server.rs
that could use cleaning up.