Dev.to WebDev 🛠 Dev 👁 0 📖 4 min read

Twenty checkout sessions, zero sales — and every one of them was mine

My store dashboard said this: page_view 11 checkout_start 9 purchase 0 An 81.8% view-to-checkout rate and a 0% close rate. Two ways to read that. Either my pricing is catastrophic, or the top

My store dashboard said this:

page_view        11
checkout_start    9
purchase          0

An 81.8% view-to-checkout rate and a 0% close rate. Two ways to read that. Either my pricing is catastrophic, or the top of the funnel is fake. I spent an hour assuming the first one before I checked the second.

The top of the funnel was fake. All nine checkout opens were me.

The number that gave it away

Stripe's own list of checkout sessions was the only source I had not looked at. Twenty sessions, live mode:

status    payment_status   count
open      unpaid           15
expired   unpaid            5

Twenty sessions opened, zero paid. Fine, that is just low traffic, right? No. Look at what the sessions actually contained:

created     status   amount  currency  product
...4712137  open     4700    brl       ship-your-mcp-server
...4711914  open     14700   brl       pack-completo
...4711913  open     4700    brl       mcp-oauth-debug
...4708349  open     6700    brl       guia-agente-que-entrega
...4705960  open     4700    brl       visual-regression-gates
...4705958  open     4700    brl       visual-regression-gates
...4705957  open     4700    brl       visual-regression-gates

Three sessions for the same product within three seconds. Eleven different products inside a few minutes. One payment method list on every single session. That is not a customer comparing options. That is a script walking the catalog, and the script had my IP.

I had been testing checkout links after a deploy and never cleaned up the signal. Then I read the dashboard, saw 81.8%, and started writing a plan to fix a conversion problem that did not exist yet.

Why the dashboard could not tell me

Every analytics stack will tell you "a checkout started". Almost none will tell you "a customer started a checkout". The event has no buyer attached to it, so a bot, a probe, your staging run and a real person land in the same counter.

The fix is not a better dashboard. It is attaching evidence to the event, at the moment it is written:

  • Identity. Was the request from my own IP, my own cookie, or a header my test harness sets? Those events get a dono class, not a customer class.
  • Timing. Sessions per IP inside a sliding window. Three in ten minutes is a comparison shopper being unlucky. Eleven in thirty seconds is a walker.
  • Payment method surface. If every session exposes the exact same method list and none progresses, nothing human is in the loop.
  • Status, not just creation. open and unpaid is not a sale. A dashboard counting session creation as intent will always look better than the business.

That last one is the whole bug in one line: I was counting my intent to test, not their intent to buy.

The class of bug that keeps paying me visits

I have written about this shape before, in three other costumes:

  • A regex that matched a single digit, so 1.234 silently became 1, and a dashboard read the same number for three weeks.
  • A guard reading a database that no longer received events, reporting "0 pending" with full confidence.
  • A watchdog restarting services at boot because systemctl is-active returns non-zero for activating.

Same shape every time: the check reports on a proxy, the proxy drifts from reality, and the report stays green. You do not fix this by being more careful. You fix it by making each number answer a narrower question with its evidence attached. Not "did a checkout start" but "which person started how many checkouts, from where, and did any of them finish".

What the real funnel looks like now

Once test traffic is excluded, the honest numbers on my store are small enough to be embarrassing and useful at the same time:

  • 29 human visitors in two days of measurement
  • 2 leads, both from the free skill
  • 0 sales, from anyone, ever

Nine checkouts at 81.8% was a story I could act on. Twenty-nine humans and no sale is a different story: there is no conversion data yet, because there is not enough traffic to convert. Optimising a page that 29 people saw is a way to feel productive.

So the fix went in the other direction. I made the test traffic visible instead of removing it, because the next person to read the dashboard needs to know which class of visitor produced the number:

def classifica_visitante(ua, ip, dono_header, cookie_dono):
    if dono_header or cookie_dono:
        return "dono", "marcado"
    if ip and ip in IP_DONO:
        return "dono", "ip_dono"
    if _BOT_RE.search(ua or ""):
        return "bot", "ua_bot"
    if _REAL_BROWSER_RE.search(ua or ""):
        return "humano", "ua_navegador"
    return "incerto", "ua_desconhecido"

The incerto class matters more than it looks. The previous version defaulted unknown traffic to "human", and a single probe generated 61 page views attributed to one person. Absence of evidence is not evidence of a customer.

One caveat I now carry: adding a classification column to a table does not retroactively classify history. My own first read of the new dashboard showed 323 "uncertain" visitors and looked like a traffic spike. It was the column's default value on rows written before the column existed. If a metric changes shape on the day you shipped it, that is the migration, not the market.

The rule I keep

Before writing a single line about conversion, click the path yourself with the data open. The gap between "the dashboard says" and "the provider says" was twenty sessions and one hour. The provider knows who paid. The dashboard knows who loaded a pixel.

Series start (if you landed here first): https://dev.to/samuelfmedeiros/a-marketplace-price-is-retail-not-cost-how-not-to-build-margin-on-the-wrong-number-2oek

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.