Documentation
Installation
MCAT requires Chrome Chrome installed on the device.
macOS
MCAT is currently available for macOS only, on Apple Silicon Macs (M1 or later). Intel Macs are not supported.
Download the latest macOS build →
- Unzip the download and move MCAT.app into your Applications folder.
- Open it. macOS will refuse and warn you the app is from an unidentified developer. This is expected: MCAT is research software distributed outside the App Store, so it isn’t signed by Apple.
- Open System Settings → Privacy & Security and scroll to the Security section at the bottom. You’ll see a note that MCAT was blocked; click Open Anyway and enter your password.
Linux and Windows
Linux and Windows support is coming. In the meantime, you can build from source by following the build section on GitHub.
First run
Prepare your input data
MCAT takes a CSV of URLs in and writes a CSV of results out. The only requirement is one column of URLs. Every other column passes through to the output CSV untouched. The smallest valid CSV file is:
url
https://www.youtube.com/watch?v=QI87UoRlfIY
https://www.youtube.com/watch?v=_eMrAZLorQs To try a first run without assembling urls, download one of these samples:
Create a project
A project is a folder. Its project.json holds the configuration; the input CSV and every run’s results sit beside it, all as plain CSV. Avoid editing any of the project’s CSVs directly: each URL carries an index that MCAT allocates and tracks, and edits outside the app can corrupt the project. To analyse or edit output CSV from a project it’s recommended to copy the desired file and work on it elsewhere on your disk. In the app, click New Project and fill in five fields:
- Project Name: the folder name.
- Project Location: where to put it. Keep it outside the app folder, since updating MCAT deletes anything stored beside the app.
- Platform: YouTube, Instagram, Facebook, or X. One platform per project.
- Source CSV: your input file.
- URL Column: pick the column that holds the URLs.
Setting up MCAT with consent and login cookies
Cookies are small pieces of data a site stores in your browser so it remembers you between page loads. They let MCAT see a platform as a logged-in user would, removing login walls and consent walls from the scraped data. MCAT stores two kinds of cookies:
Consent cookies record that you answered the platform’s cookie or privacy banner. They belong to the browser, not to you, and carry no account information. Dismissing the banner once is what they preserve.
Login cookies are the session token the platform issues after you sign in. They are what proves to the platform that a request comes from your account, and they are the reason MCAT can see what a logged-in visitor sees.
Always create a new throwaway account for each platform, never use your personal one. MCAT never stores passwords, only cookies.
Click **Set up browser**. A Chrome window opens. Dismiss the cookie banner and log in where needed. MCAT stores the resulting cookies inside the project and reuses them until they expire.How are session cookies stored
MCAT stores cookies in cookies/<platform>.json of the project folder, one file per platform, readable only by your user account. Cookies never leave your machine. MCAT has no account, no server, and no telemetry, and the file is only ever read back to rebuild the same browser session. Anyone who gets this file is signed in as that account without needing your password or a 2FA code, and can read its private messages, post as it, and change its settings or lock you out, until the cookies expire.
To avoid leaking cookies, delete the cookies folder before sharing or publishing a project folder. Reset browser in the respective project does the same thing, and a good habit is to reset once you’re done with a project.
Run it
Before you start, leave Save screenshots on unless you have a reason not to: screenshots let you check MCAT’s verdict by eye, and they are evidence of what the page looked like at that moment.
Click Start. Every URL resolves to one of seven content states: live, restricted, moderated, unavailable, login_required, unknown, or error. The progress bar fills by state as URLs resolve, and the activity log prints each check. Pause stops after the in-flight checks finish. Resume picks up where it left off. Abandon discards the run.
Read the results
Each run appears in the timeline. Click one to expand it:
- All Results: every URL and the state it resolved to.
- Changes: what moved since the previous run. Empty on the first run.
- Run Info: when it ran, how long it took, which account was used.
Run Folder opens the run on disk:
my-project/
├── project.json
├── urls.csv
└── runs/
└── 2026-01-14_1030/
├── results.csv
├── changes.csv (second run onward)
└── screenshots/
├── live/
├── unavailable/
└── … results.csv is your input CSV plus:
- mcat_status: the content state.
- mcat_detail: the specific reason, such as age-restricted or removed by uploader.
- mcat_screenshot: the path to the page screenshot.
- mcat_timestamp: when it was checked.
- mcat_error: why a check failed, if it did.
- mcat_user: which account was used, stored as the platform’s internal numeric account ID.
Check again over time
Set Repeat every to an interval in minutes, hours, or days. MCAT re-checks the same URLs on that schedule. The first completed run in a project is its baseline. It records the starting state and its Changes tab stays empty. Every run after that is compared against the run immediately before it, matching URLs between the two runs and reporting the ones whose state differs.
Abandoned runs are skipped, so the comparison always reaches back to the last run that finished. From the second run on, each run folder also gets a changes.csv alongside results.csv, listing every changed URL with its previous and new state.
Adding new URLs to a project
A project’s URLs are fixed when you create it. When you have new URLs to track, create a new project.
Content states
Every checked URL resolves to one content state. A few states only occur on certain platforms.
- Live Loads and is publicly viewable. All platforms.
- Restricted Present but access-gated, such as age-restricted, geo-blocked, or private. YouTube and X.
- Moderated Taken down by platform enforcement, such as a suspended account or terminated channel. YouTube and X.
- Unavailable Gone: deleted by the uploader, a 404, or expired. All platforms.
- Login Required An auth wall blocked the check; the content itself may still be live. Instagram.
- Unknown Loaded but nothing matched, left for a human to judge from the screenshot. All platforms.
- Error The check itself failed: no load, a timeout, or a crash. All platforms.
States by platform
Which states occur, and how reliably they are told apart, varies by platform.
YouTube
Tells apart Live, Unavailable, Restricted, and Moderated. It reads the visible page text for removal, age, geo, private, and channel-termination markers, and confirms Live from the rendered video title. Run it once through Set up browser to capture the consent cookie; without it, checks are redirected to a consent page.
Works without login, since Instagram shows post previews to anonymous visitors. It reads Unavailable from the page title and error state, and confirms Live from the post caption. When a login wall is the only signal it reports Login Required, so log in through Set up browser for fuller coverage.
The coarsest of the four: in practice it only separates Live from Unavailable. Unavailable pages load fast with a clear error; live pages render slowly. Every anonymous page embeds a login form, so there is no reliable Login Required signal and undecided pages fall back to Unknown.
X
Renders a tweet card only when a post is genuinely live, so a card is conclusive Live, checked before any takedown phrase. Run it logged in through Set up browser: logged out, X throttles even live tweets to a generic page that misreads as Unavailable.