Almost everyone who builds a lead score builds the wrong object. They try to compute lead quality, as though quality were a property of the prospect. It is not. A lead is not good or bad in the abstract; it is good or bad for one offer, at one price, in one window of time. Get that wrong at the design stage and no amount of arithmetic afterwards will rescue the output.
What follows is a build guide on top of the fields an ecommerce API actually gives you: domain, platform, country, productCount, monthlyTraffic, organicKeywords, apps, paymentMethods, contactEmail, the Google Business block, the trend series. Gates, signal families, weights, normalisation, decay, calibration. It is more boring than a machine learning post and it will work in month nine, which is the part that matters.
Score one offer, or the score means nothing
The number has to answer a question narrow enough to be falsifiable: how likely is this store to buy this specific thing, at this specific price, in the next ninety days? If you sell three things, you build three scores. That feels like triple the work and is actually less, because each one is simpler and each one can be debugged independently.
The cost of ignoring this is subtle and expensive. A single blended score will consistently rank a forty-thousand-SKU distributor above a three-hundred-SKU direct-to-consumer brand, for everything, because the distributor is bigger on every axis you measured. It is the right lead for your feed-management offer and completely wrong for your creative offer, and the blended number cannot express that.
Name them accordingly and boringly. A score field called score_local, one called score_cro, one called score_feed. Names that survive contact with a second person on the team are worth more than elegance.
Gates before points
Disqualification is faster and cleaner than ranking, and salespeople who are genuinely good at outbound spend most of their energy removing people from the list rather than sorting them. Build the same instinct into the model. A gate is a boolean that, when it fails, removes the record entirely — no points, no partial credit, no appearing at the bottom of a view where somebody will eventually work it out of desperation.
The gates are usually obvious once you write them down: platform in your supported set, country in a language you can sell in, productCount above the floor where your work has anything to act on, monthlyTraffic above the level where a percentage improvement is a real number, not already a customer, not in any suppression list.

Applied first, gates take 153,515 stores down to a few thousand before a single point is computed. Everything downstream becomes cheap, and more importantly, everything downstream becomes reviewable by a human who can actually read the list.
Three families of signal, and only three
Capacity to pay, evidence of the problem you solve, and reachability. If a candidate signal does not belong to one of those three families, it is a description of the prospect rather than a predictor of the sale, and it does not belong in the score. This rule alone kills about half the fields people are tempted to include.
Capacity draws on monthlyTraffic, productCount, the price band you derive from the catalog, reviewsCount as a rough proxy for operating history, platform as a proxy for sophistication and budget, and the detected app stack — a store paying for six subscription apps has demonstrated, with money, that it buys software. That last signal is underrated because it is behavioural rather than declarative.
Evidence is whatever your offer fixes, expressed as data. A feed agency looks for a large catalog with no shopping-related app detected. A conversion consultancy looks for meaningful traffic alongside a thin payment method list or a poor keyword-to-product ratio. A local specialist looks for an unclaimed profile, near-zero photos, a rating under four. An email agency looks for a repeat-purchase price structure and no email service provider in the stack.
Reachability is unglamorous and decisive: contactEmail present, socials present, a phone or address on the Google profile. A perfectly qualified store you cannot contact is worth exactly zero, and pretending otherwise inflates your list with rows that will never convert into anything.
Weights: hand-set, then argue about them
You do not have enough closed deals to fit a model, and neither does anyone else at the start. Twelve wins will not support a regression, and a model fitted on twelve wins will confidently encode the accidents of your first quarter. Assign weights by hand, in round numbers, and write the reasoning in a comment next to each one.
A reasonable starting shape is evidence fifty, capacity thirty-five, reachability fifteen, with no more than four or five inputs inside each family. Adding a twelfth input feels like rigour and is almost always noise, because the twelfth input correlates with the third and you have quietly double-counted.

Use bands rather than linear functions. Traffic under a thousand scores zero, one to ten thousand scores ten, ten to fifty thousand scores twenty-five, above fifty thousand scores thirty. Bands are legible to a human, they degrade gracefully when the underlying estimate is off by forty percent — and traffic estimates are off by forty percent all the time — and they can be audited by someone who does not write code.
Cap the total at a hundred and never let a single input exceed about thirty. If one field can push a record into the top decile alone, you have not built a score, you have built an expensive alias for that field.
Normalise across country, platform and category
Absolute thresholds systematically punish small markets. Three thousand monthly visits on a Dutch store may represent a healthier, more profitable business than three thousand on a US store in the same category, because the addressable market and the competitive intensity are different. Score them identically and your list will drift American and Shopify-shaped without anyone deciding that it should.
The fix is percentile within cohort rather than raw value. Compute the traffic distribution per country and platform pair, then score the store’s percentile inside its own cohort. It costs one extra aggregation in the pipeline and removes a bias that would otherwise take you six months to notice.
Apply the same treatment to productCount, which means genuinely different things on PrestaShop and on JouwWeb, and to reviewsCount, which varies enormously by category and by national review culture. A four-hundred-review restaurant supplier and a four-hundred-review boutique are not comparable objects.
Recency, decay and the fields that age differently
A score computed in March and used in September is a lie with a timestamp. Attach a computed_at to every score and decay your confidence in it rather than the number itself. After ninety days, flag it stale in the interface. After a hundred and eighty, refuse to let it feed a sequence at all.
Fields age at wildly different rates and your refresh schedule should reflect that. Traffic and trend age in weeks. Detected apps and contact emails age in a couple of months. productCount ages in months. Country and platform age in years — except when a store replatforms, which happens constantly and is itself one of the strongest buying signals in the dataset.
In practice: a monthly job over your active segment refreshing the volatile fields, a quarterly job over everything refreshing the structural ones, and a liveness check immediately before any sequence launches. Three jobs, and they will save you more money than any copy improvement you make this year.
Calibration is the only part that makes the score real
A score with no outcome feedback is astrology performed with arithmetic. The mechanism that turns it into something real is trivially simple and almost universally skipped: write the score into the CRM at the moment of first contact, freeze it there, and then compare deciles against replies, meetings booked and deals closed.
What you are testing is monotonicity, not accuracy. If the top decile replies better than the fifth, and the fifth better than the first, the score is doing its job even if the absolute numbers are unflattering. If the deciles are flat, one of your three families is wrong — and it is nearly always evidence, because people instinctively score what is easy to measure rather than what predicts a purchase.

Review quarterly, change one thing per review, and keep the previous version’s definition so you can compare cohorts honestly. Changing four weights at once and then observing that things improved teaches you nothing you can reuse.
A worked shape, and the failure modes in order of frequency
A conversion freelancer selling a €4,500 audit-plus-retainer might set gates at Shopify or WooCommerce, an EU country, traffic above eight thousand, contactEmail present. Evidence: median price at or above €60, productCount between one hundred and three thousand, no conversion-adjacent app detected, positions rising while traffic sits flat. Capacity: traffic percentile within cohort, reviewsCount band, count of paid apps. Reachability: email plus at least one social profile. Five to twelve inputs total, all of them defensible out loud.
The failure modes, roughly in order of how often they occur: scoring what is easy to measure instead of what predicts; too many inputs; letting one field dominate the total; never freezing the score at contact time, which makes calibration impossible forever; and building an immaculate score for an offer nobody actually wants, which is a problem no arithmetic has ever solved.
Keep the ambition modest and the score becomes genuinely useful. It does not sell anything and it does not predict revenue. It decides what order you work in, and it lets you stop thinking about a hundred and forty-eight thousand stores. That is the entire value proposition, and it is more than enough.
