# SMM panel price-and-claims survey — methodology

**Survey date:** all pages read between **2026-09-02T00:16:39Z and 2026-09-02T00:16:51Z** (a 12-second window, so every panel is priced at the same moment).
**Second capture:** the same fifteen pages read again between **2026-09-13T20:27:59Z and 2026-09-13T20:28:11Z**. See section 8.
**Surveyor:** Novamya editorial. **Sample:** 15 panels, 44,064 listed services.

## 1. What this is

A one-shot, machine-read snapshot of what public SMM panel service catalogues *say* — names, listed prices,
order limits, and the delivery/refill claims printed next to them. Nothing here was bought, ordered or delivered.
Every number in `services-basket.csv` was read off a public web page; none was estimated, converted, or inferred.

## 2. How panels were chosen

Selection was constrained by one hard rule: **the full service catalogue had to be readable on a public URL with
no account, no login, and no form submission.** No accounts were created; no orders were placed; no forms were
submitted anywhere.

Candidates came from three places:

1. **The publisher's own two panels** — `smmlaunch.com` and `adderpanel.com`. These are commercially connected to
   Novamya's publisher and are labelled `publisher-owned (disclosed)` in the CSV. They were included deliberately
   so that a reader can check whether the publisher's panels are being flattered by the sample. On the basket item
   the most panels carry they are 10th and 11th cheapest of 12; on the other three they sit at or near the middle,
   and on the Instagram followers row the median printed in the article is their own price. Check it in
   `services-basket.csv` rather than taking the sentence.
2. **Google, via two Serper API queries** (`gl=us`, `hl=en`), routed through an OVH Montréal relay because this
   workstation's IP is blocked by that API:
   - `best smm panel list telegram members instagram followers services price list`
   - `"Rate per 1000" "Min order" "Max order" smm panel services telegram members`
   The two query strings above are the record; the raw API responses are third-party output and are not
   republished here.
3. **Outbound links on `socpanel.com`**, a public panel directory, which yielded a further 17 domains.

Every candidate's `/services` and `/service` path was then fetched and tested for a machine-readable price table.
Fetches ran from a Hetzner Helsinki host with a desktop Chrome user-agent, because this workstation is in Iran and
several of these hosts geo-block it. Only the public `/services` page of each panel was requested — one GET per panel.

## 3. What was excluded, and why

| Excluded | Reason |
|---|---|
| `justanotherpanel.com` | `/services` renders a login form; catalogue is behind an account |
| `smmfollows.com`, `yoyomedia.in`, `n1panel.com`, `bulkfollows.com` | `/services` returns marketing copy only; the catalogue loads over JavaScript after auth |
| `smmbin.com`, `b2bsmmpanel.com` | HTTP 403 to our fetch |
| `top4smm.com`, `smmheaven.net` | HTTP 404 / empty response |
| `socpanel.com` | It is a directory that re-lists *other* panels' services; including it would double-count them |
| `bharatsmmpanel.com` | Only 9 services on the public page — too thin to characterise a catalogue |
| `growfastsmm.com` | **Retained in the corpus but excluded from every USD comparison**: it prices in ₹ (INR). Converting would require an FX rate we did not observe, and this survey does not estimate numbers |

`peakerr.com` is **retained in the corpus but excluded from every price comparison.** The requested URL
`https://peakerr.com/services` redirected to `https://peakerr.com/` — `fetchlog.tsv` carries both the URL asked for
and the URL that answered — and what came back is a marketing summary of 8 headline services with a price and a
delivery word each. Its rows have no service id, no category, no min and no max. They are advertised headline
prices, not catalogue entries comparable with the others. Its rows still count towards the claim percentages,
which are measured over every USD-priced panel; they are excluded from the basket spread and from the same-name
price gaps. The first published version of the article did not exclude them, and one of them — a $0.05 YouTube
views row — was printed as the cheapest YouTube listing in the spread table.

## 4. How the basket was picked

Four services most panels actually carry: **Telegram channel members, Telegram post views, Instagram followers,
YouTube views.** A service counts for a basket slot if its name or category matches a platform keyword plus a
product keyword, and matches none of an exclusion list (e.g. a "Telegram members" row must not also say *view,
reaction, vote, poll, report, bot start, session, tdata, account, gift, auto*). The exact predicates are in
`analyse.py` (`is_tg_members`, `is_tg_views`, `is_ig_followers`, `is_yt_views`) and are the definition of record.

Where a panel lists many qualifying services — and most list dozens — the CSV row is the **cheapest eligible one**.
That rule was chosen because it is mechanical and re-checkable by anyone with the same files, and because it is the
number a panel is implicitly advertising when it says "from $X". The CSV also carries that panel's min, median and
max across *all* its qualifying services, so a reader can see how much the "cheapest" choice is doing.

**Eligibility filter** (applied before choosing the cheapest, to keep the comparison honest):

- A price quoted "per 1,000" is only comparable if 1,000 units can be ordered, so services that do not **publish a
  maximum order of at least 1,000** are dropped. That removes 2,844 of 44,064 rows whose stated maximum is under
  1,000 — most of them single-unit account sales and "make a ticket" placeholders — and the 8 rows that state no
  maximum at all, which are all of `peakerr.com`'s. The first version of this test read
  `if m is not None and m < 1000`, so a row with no published limit passed a filter written to require one; a
  missing maximum is not a large maximum.
- Services filed under a category heading matching *don't use / do not use / deprecated / disabled / test only*
  are dropped. On `smmlaunch.com` this alone removes a $0.01 Telegram Premium Members row that sits in a category
  the panel itself names **"Dont use!"**; without this rule that row would have been the survey's headline low price.
- Rows whose name is an instruction rather than a product (*ask me, make ticket, contact us, do not order*) are dropped.
  This removes `easytopromo.com`'s "ASK ME ANY TYPE OF ADWORDS VIEWS" at $0.0001 with min 1 / max 1, which would
  otherwise have produced a fake **19,000×** spread in the YouTube column ($0.0001 to $1.90) against the 11.2×
  the filtered comparison gives. An earlier version of this note put that figure at 28,800×; it does not
  reproduce from the stored data and no combination of the three filters produces it.
- Rows whose name starts with *test* (or *id test*) are dropped. This fourth filter was added on 13 September
  2026, when the second capture turned up a new $0.15 row on `smmlaunch.com` named only `Test`, filed under a
  Telegram members category, which would otherwise have become that panel's cheapest Telegram members listing.

**One basket predicate was tightened on the same day.** `is_ig_followers` now also excludes names or categories
containing *member*: `autosmo.com` files a service called `Instagram Channel Members` under an "Instagram Followers"
heading, and in the second capture that row became the panel's cheapest "followers" listing.

Applied to the 2 September capture, the two changes alter two rows of `services-basket.csv` and no published figure.
`1xpanel.com`'s Telegram members row: qualifying listings 823 → 822 and panel median $2.3796 → $2.3648, because
`Test Server - Telegram Online Members` stops counting. `autosmo.com`'s Instagram followers row: qualifying listings
55 → 54 and panel median $3.9300 → $3.9150; its cheapest listing is unchanged at $1.17. `stats.json` is
byte-identical with and without both changes.

## 5. How the claims were read

`start_time_verbatim`, `delivery_speed_verbatim` and `refill_guarantee_verbatim` are **quoted from the page, not
paraphrased**. They are extracted from the service name plus, on the two panels that print descriptions in the HTML
(`1xpanel.com`, `morethanpanel.com`), the description text. Ordering of the refill patterns matters and is
deliberate: the qualifier in front of the word carries the meaning, so `No Refill` and `30 Days Refill` are matched
before the bare word `refill`. Anything not found is recorded as **`not listed`** — never guessed.

The `avg` column is read the same way and counted more narrowly. A cell counts as a stated completion time only if
it **contains a digit** and is not the one identifiable parse failure (`smmfolgen.com`, where the cell captured the
whole table row and can be recognised by the leaked `Rate per 1000` header). That test exists because counting every
non-empty cell counted 5,251 `New Service` cells on `1xpanel.com`, 6,769 on `crescitaly.com`, six `Instant` cells on
`peakerr.com` and all 123 smmfolgen rows — 12,149 cells that state no duration, and in the `New Service` case state
that the panel has none yet. Non-empty: 23,590 of 43,812 (53.8%). Containing a duration: **11,441 (26.1%)**. The
narrow count is the one the article publishes; `analyse.py` prints both.

The five Perfect-Panel-style sites (`smmlaunch`, `adderpanel`, `crescitaly`, `smmcost`, `smmkings`) hide their
service descriptions behind a JavaScript "View" button that fetches over AJAX. We did not execute their JavaScript,
so for those panels a claim counts as "stated" only if it appears in the service name itself. This **understates**
their disclosure and is the single biggest known bias in the claim percentages. It does not affect any price.

## 6. What these numbers can and cannot support

**Can support:** what 15 public catalogues listed, in USD, at 2026-09-02T00:16Z; how far apart their listed prices
are; how often a listing names a start time, a delivery rate or a refill period; and which catalogues share
verbatim service-name strings with which others.

**Cannot support:** anything about delivery. Not one order was placed. A listed price is an asking price; a listed
"30 Days Refill" is a promise, not an observed outcome; a listed "average time" is the panel's own unaudited
statistic. Nothing here shows that the cheap panels are worse, that the expensive ones are better, or that any of
them deliver at all.

**Also cannot support:** ownership claims. Identical service-name strings across two panels are consistent with a
shared upstream supplier, but they are equally consistent with one panel copying another's catalogue text. The
survey measures the string overlap and stops there.

**Sample bias to keep in mind:** this is a sample of panels that *choose* to publish a catalogue publicly. Panels
that put their prices behind a login — including `justanotherpanel.com`, one of the largest — are absent by
construction. Prices at 00:16Z on one night are not prices in general; several of these panels stamp update dates
on their categories, so the catalogues visibly move.

## 7. Reproducing this

Everything named here is published at <https://novamya.com/data/panel-price-survey/>.

`pages/` holds the gzipped HTML of all 15 catalogues exactly as fetched, and `fetchlog.tsv` gives, per panel, the
URL requested, the UTC timestamp, the HTTP status, the URL that actually answered, and the byte count.
`parse_panels.py` turns `pages/` into `services-all.json.gz` (all 44,064 rows); `analyse.py` turns that into
`services-basket.csv` and `stats.json` and prints the aggregate tables. Both scripts read and write the directory
they live in, so:

```
python3 parse_panels.py     # pages/*.html.gz  ->  services-all.json.gz
python3 analyse.py          # services-all.json.gz + fetchlog.tsv -> services-basket.csv, stats.json
```

Re-running them against the stored HTML reproduces every number in this survey without touching the network. If a
figure on the article does not come out of that, the article is wrong and we want to be told.

Until 13 September 2026 `parse_panels.py` named a temporary directory on the laptop that parsed the first capture and
wrote an intermediate `_parsed.json` there, so the published parser could not run on the published pages as this
section claimed. It now reads `pages/` next to itself and writes `services-all.json.gz` directly. Checked after the
change: run on `pages/`, it rebuilds the published `services-all.json.gz` with all 44,064 rows identical, and
`analyse.py` then rebuilds `stats.json` byte for byte.

For the second capture and the comparison:

```
python3 parse_panels.py w2  # pages/w2/*.html.gz  ->  services-all-w2.json.gz
python3 analyse.py w2       # -> services-basket-w2.csv, stats-w2.json
python3 compare.py          # both captures -> changes.json, price-changes.csv, renamed-listings.csv
```

## 8. The second capture, and how the two are compared

**When and how.** The fifteen `/services` URLs in `harvest.sh` were fetched again on 2026-09-13 between 20:27:59Z
and 20:28:11Z, from the same Hetzner Helsinki host, with the same user-agent, one GET per panel, in the same order —
eleven days, twenty hours and eleven minutes after the first. Every request returned HTTP 200; `peakerr.com/services`
again redirected to the homepage. Before fetching, each panel's `robots.txt` was read; none disallows `/services`.
The raw pages are in `pages/w2/`, the log in `fetchlog-w2.tsv`. The parser's reading rules needed no change: all
fifteen tables carried the same column headers as eleven days earlier. Two things in this paragraph are not
checkable from the published files: the fetch log records no source address, and the `robots.txt` files were
read but not stored.

**The join.** A listing is the same listing in both captures when the panel and the panel's own service id match.
That id is what an order is placed against, so it is the panel's definition of "this service", not ours. It has a
known weakness, and the data shows it: a panel can put a different product behind an old id. 135 listings kept their
id and changed their name; all of them are in `renamed-listings.csv`, and the basket comparison labels a
same-id move as "renamed and repriced" whenever the name changed too. `peakerr.com` has no ids and is joined on its
eight names; it is reported and kept out of every price figure, as before. `growfastsmm.com` is joined but kept out
of every figure because it prices in rupees.

**What counts as a change.** A kept listing is *repriced* when its listed rate per 1,000 differs between captures.
Change is `(second − first) / first`. A listing is *withdrawn* when its id is on the first capture and not the second,
and *added* the other way round. None of this says why: a withdrawn listing may be disabled, moved behind a login,
or renumbered.

**Same-factor blocks.** Ten or more listings on one panel whose price ratio between captures is equal to three
decimal places are counted as a block — one rule applied to many listings rather than many decisions. Ten is
arbitrary (`BLOCK_MIN` in `compare.py`). Rounding matters here: blocks at 0.980, 0.981 and 0.982 on the same panel
are very probably one 2% rule seen through rounded prices, so the number of blocks overstates the number of rules,
and because pieces under ten are not counted, the share of changes in blocks is a lower bound. Each block also
records how many different starting prices it spans (`distinct_old_prices`): a block whose listings all started at
one or two prices is a product line repriced together, not a rule proportional across a catalogue. The cause of any
block is inferred, not observed.

**What two captures cannot support.** A difference between two dates, not a trend. Nothing here says whether eleven
days of movement is typical, seasonal, or a one-off, and — as with the first capture — nothing says anything about
delivery.
