Metadata-Version: 2.4
Name: snapchat-scraper-api
Version: 0.0.1
Summary: Snapchat scraper API client: public profile data, follower counts and Spotlight videos via ScrapingBee.
Author: wordstotech
License: MIT
Project-URL: Homepage, https://github.com/ScrapingBee/snapchat-scraper-api
Project-URL: Repository, https://github.com/ScrapingBee/snapchat-scraper-api
Project-URL: Documentation, https://www.scrapingbee.com/documentation/
Keywords: snapchat scraper,snapchat api,snapchat profiles scraper,snapchat data scraper,web scraping,scrapingbee
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Text Processing :: Markup :: HTML
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.25.0
Dynamic: license-file

# snapchat-scraper-api

A Python client for public Snapchat profile data through ScrapingBee. Built around the fact that most selectors on a Snapchat profile are guaranteed to break, and the ones that are not live somewhere unobvious.

**Verified against `snapchat.com/add/teamsnapchat` and `snapchat.com/add/mrbeast` on 2026-09-10.** Three findings below only surface on a live run: there are two incompatible page layouts, the follower count is not in the visible text at all, and the page language depends on which country the request left from.

```bash
pip install snapchat-scraper-api
```

Requires Python 3.8 or newer and `requests`.

## The cheapest target in the series

One credit per profile. Snapchat serves these pages as delivered HTML, so `mode=auto` settles on the plain rung and never opens a browser. Do not add `render_js` out of habit, it buys nothing here and costs five times more.

## What is in scope

Public profile pages, read anonymously: display name, username, subtitle, Snapcode, preview image, canonical URL, follower count, profile creation and last modified dates, Snapchat's family friendly flag, and public Spotlight or highlight videos.

Out of scope: private accounts, friend lists, Snap Map location data, direct messages and story view data. Those need a signed in session, and scraping under login credentials is prohibited by ScrapingBee's terms of service.

## Authentication

```python
from snapchat_scraper_api import SnapchatScraper

bee = SnapchatScraper("YOUR_API_KEY")
```

Sent as `Authorization: Bearer YOUR_API_KEY`. Key and 1,000 free credits: [ScrapingBee](https://www.scrapingbee.com/). Landing page: [Snapchat scraper API](https://www.scrapingbee.com/scrapers/snapchat-scraper-api/).

---

## Method reference

### `profile(username, country=None)`

**1 credit** unpinned, **25 credits** with a country pinned.

```python
bee.profile("teamsnapchat")
```

```python
{'display_name': 'Team Snapchat',
 'username': 'teamsnapchat',
 'subtitle': 'Add me on Snapchat!',
 'snapcode': 'https://app.snapchat.com/web/deeplink/snapcode?username=teamsnapchat&type=SVG&bitmoji=enable',
 'profile_image': 'https://www.snapchat.com/web-capture/www.snapchat.com/@teamsnapchat/preview/square.jpeg?xp_id=1',
 'og_title': 'Team Snapchat on Snapchat',
 'og_description': 'Team Snapchat is on Snapchat!',
 'canonical': 'https://www.snapchat.com/@teamsnapchat'}
```

The same call works on a creator profile, which matters more than it sounds.

**Snapchat serves two incompatible layouts.** Both handles below were fetched with one rule set:

| Selector | `teamsnapchat` (basic card) | `mrbeast` (creator profile) |
|---|---|---|
| `h1 span` | empty | `MrBeast` |
| `h4 span` | `Team Snapchat` | empty |
| `h5 span` | `teamsnapchat` | wrong node, the page has ten `h5` elements |
| `[data-testid="snapCodeImage"]` | the Snapcode URL | empty |

They are mutually exclusive. This client requests both headings and returns whichever is populated, so one call covers both page types. A scraper written against only `h4 span` works on half of Snapchat and returns empty strings on the other half, with a 200 status and no error.

Three more decisions the client makes for you:

- **The username comes from the canonical URL**, not from a heading. The canonical is byte identical across layouts and does not change with locale, and it always reads `https://www.snapchat.com/@<username>`.
- **The Snapcode is rebuilt when the selector is empty.** The endpoint is parameterised by username, and the constructed string matches the live selector value exactly, verified on both handles. No second request.
- **An empty dict means the handle has no public page.** More on that below.

**Never select on CSS module classes.** Snapchat ships class names like `UserDetailsCard_title__K9Awz`, `Heading_h400Emphasis__SQXxl` and `DesktopUserProfile_desktopContainer__UwOc_`. The suffix after the double underscore is a build hash. It rotates on deploy, and a scraper keyed on it silently returns empty strings afterwards.

### `stats(username, country=None)`

**1 credit.** Follower count and account dates, from the `application/ld+json` block.

```python
bee.stats("mrbeast")
# {'name': 'MrBeast',
#  'username': 'mrbeast',
#  'url': 'https://www.snapchat.com/@mrbeast',
#  'image': 'https://cf-st.sc-cdn.net/aps/bolt/...',
#  'followers': 1463400,
#  'created': '2019-05-16T14:46:37.345Z',
#  'modified': '2026-08-13T13:01:39.438Z',
#  'locale': 'en-US',
#  'family_friendly': True}
```

**The follower count is not in the visible text.** The DOM carries the i18n template placeholder, literally `{subscriberCount} suscriptores`, so a text selector returns the template rather than a number. The real value sits in `interactionStatistic`, in the counter whose `interactionType` is `FollowAction`. This client digs it out.

`created` and `modified` are the other two fields available nowhere else. `modified` is how you separate an active creator from a dormant handle without fetching a single post.

Returns `None` when there is no public profile page.

Note this parses the fetched HTML rather than using `extract_rules`, because **`extract_rules` cannot read script tag contents**. A rule selecting `script[type="application/ld+json"]` returns `None`, tested directly.

### `spotlight(username, country=None)`

**1 credit.** Public Spotlight and highlight videos, from the `ItemList` block.

```python
bee.spotlight("mrbeast")
# [{'url': 'https://www.snapchat.com/@mrbeast/highlight/91542d31-...',
#   'name': 'A Snapchat video by MrBeast',
#   'description': 'A Snapchat video by MrBeast',
#   'thumbnail': 'https://cf-st.sc-cdn.net/d/...'}, ...]
```

Five entries on the creator page tested. **An empty list is normal, not a failure.** The same block came back as an empty array on `teamsnapchat`.

### `exists(username)`

**1 credit.** Whether the handle has a public profile page.

```python
bee.exists("teamsnapchat")  # True
bee.exists("dailymail")     # False
```

A missing handle answers in two different ways, and both were observed on the same handle at different times. One capture returned HTTP 200 with a 5,973 byte body, a bare `Snapchat` title and no `ProfilePage` block. A later capture returned a real **HTTP 404**, forwarded straight through because 404 is one of the few statuses ScrapingBee does not rewrite.

This client treats both as "no page" rather than raising, so a batch run does not die on one bad handle. Decide on the presence of the `ProfilePage` block, not on the status code.

### `snapcode_url(username, svg=True, bitmoji=True)`

A static method. **0 credits, no request.**

```python
SnapchatScraper.snapcode_url("teamsnapchat")
# 'https://app.snapchat.com/web/deeplink/snapcode?username=teamsnapchat&type=SVG&bitmoji=enable'
```

### `usage()`

Free. Account credits, concurrency and renewal date.

---

## The locale trap

Snapchat localises by proxy exit IP, and without a country parameter whichever region the request left from decides the language of every title, subtitle and label you parse.

Two captures of the same creator URL, same parameters, no change in between:

```
capture 1  title: MrBeast (@mrbeast) | Historias de Snapchat, Spotlight y Lentes
capture 2  og_title: MrBeast pe Snapchat        og_description: MrBeast este pe Snapchat!
```

Spanish, then Romanian. The structured data tells you it happened, through `inLanguage`, which `stats()` returns as `locale`.

What moves and what does not:

| Field | Locale dependent |
|---|---|
| `og_title`, `og_description`, page title, visible labels | yes |
| `canonical`, `username`, `profile_image`, `snapcode` | no |
| `followers`, `created`, `modified` | no |

So pin the country only when you actually read the strings:

```python
bee.profile("mrbeast", country="us")   # 25 credits, English guaranteed
bee.stats("mrbeast")                   # 1 credit, the number is the same either way
```

Pinning gave an identical `followers` value on both runs. Geotargeting requires the premium tier, which is a twenty five times cost increase, so do not turn it on for numeric work.

## Credit cost

Measured from `spb-cost` headers. Available on `bee.last_cost`.

| Configuration | Credits |
|---|---|
| `mode=auto`, settled on plain HTML | 1 |
| `premium_proxy` with `country_code` | 25 |
| Validation error | 0 |

`mode=auto` bills only the rung that worked and nothing if every rung fails. It is incompatible with `render_js`, `premium_proxy` and `stealth_proxy`, and sending both returns HTTP 400 while billing nothing.

At 1 credit per profile, 250,000 credits covers 250,000 profile checks. Plan tiers: [ScrapingBee pricing](https://www.scrapingbee.com/pricing).

## Related

Adjacent social and creator landing pages: [Patreon scraper API](https://www.scrapingbee.com/scrapers/patreon-api/), [TikTok API](https://www.scrapingbee.com/scrapers/tiktok-api/), [TikTok search API](https://www.scrapingbee.com/scrapers/tiktok-search-api/), [TikTok follower API](https://www.scrapingbee.com/scrapers/tiktok-follower/), [Twitch API](https://www.scrapingbee.com/scrapers/twitch-api/), [Substack scraper API](https://www.scrapingbee.com/scrapers/substack-scraper-api/), [YouTube shorts API](https://www.scrapingbee.com/scrapers/youtube-shorts-api/), [YouTube video scraper API](https://www.scrapingbee.com/scrapers/youtube-video-scraper-api/), [YouTube title scraper API](https://www.scrapingbee.com/scrapers/youtube-title-scraper-api/).

Features: [data extraction](https://www.scrapingbee.com/features/data-extraction/), [AI web scraping](https://www.scrapingbee.com/features/ai-web-scraping-api/), [screenshots](https://www.scrapingbee.com/features/screenshot/), [markdown scraper](https://www.scrapingbee.com/features/markdown-scraper/), [JavaScript scenario](https://www.scrapingbee.com/features/javascript-scenario/), [n8n integration](https://www.scrapingbee.com/features/n8n/).

Reference: [extraction rules documentation](https://www.scrapingbee.com/documentation/data-extraction/). The selector durability walkthrough is at [github.com/ScrapingBee/snapchat-scraper-api](https://github.com/ScrapingBee/snapchat-scraper-api).

## License

MIT
