We Vectorized 10,024 Logos in a Day: Real Throughput, Real Costs, Real Failures
A measured benchmark of bulk image-to-vector conversion at scale: 5,574 logos in a single hour, 122 per minute at peak, what it cost, and the four things that broke along the way.
Founder of VectoSolve
Self-taught developer, founder and sole developer of VectoSolve since 2024. He builds the conversion engine and the cutting, embroidery and 3D printing exports.
How this article was made: drafted with AI assistance, then edited and fact-checked before publication. About the author
Try it on your own file
Free preview, no signup. Drop an image and see the vector before deciding anything.
Most articles about batch vectorization stop at "it scales". This one is a log. We ran 10,024 company logos through our own converter in a single working day, measured every stage, and wrote down what broke. If you are planning bulk conversion, the failures below will cost you more time than the throughput numbers will save you.
The numbers
All measured from database timestamps, not estimated:
- 10,024 logos vectorized, across 9,519 distinct domains
- 5,574 in a single hour, the busiest one
- 122 per minute at peak, roughly two per second
- Average output 78 KB of SVG, largest 6.9 MB
- 1,322 needed no conversion at all, because the source was already SVG
The last line matters more than it looks. Roughly 13% of the logos we collected were already vector. Detecting that before calling any API is the single cheapest optimization available, and it is one line of code: check whether the first few hundred bytes contain <svg.
Throughput is not the bottleneck. Other people's web servers are.
The first run was sequential and took about three hours for 620 logos. Almost none of that time was conversion. It was spent waiting on the sites the logos live on: DNS, TLS handshakes, slow shared hosting, redirects.
Moving to a bounded worker pool of 8 to 12 concurrent jobs took the same work from hours to minutes. Not higher: a paid conversion API will start returning 429s if you hammer it, and we collected a handful even at 10.
const queue = [...items]
await Promise.all(
Array.from({ length: 10 }, async () => {
while (queue.length) await handle(queue.shift())
})
)
That is the whole thing. No queue library, no orchestration. The important part is the bound, not the parallelism.
Four failures worth knowing about
1. Source images are too small, and it fails silently at scale
Logos on the web are served at display size. Six of our first twenty attempts were rejected outright for being under the API's minimum edge length. Upscaling to a 512px minimum with a Lanczos filter before conversion fixed the rejections and improved the trace, because the tracer has more edge to work with.
Yield went from 55% to 85% on the same twenty sites, from that one change.
2. Finding "a logo" is a different problem from finding "their logo"
This is the one that cost us the most. Our first picker took the first image on the page whose markup said "logo". On a sign shop's homepage, that is frequently a client logo: print shops, sign makers and promotional companies display the brands they have worked for. One site carried twelve client logos at 29% of the document, and their own mark carried no marker at all.
What actually works, in order of weight:
- Position. A site's identity lives in its header. A logo two thirds of the way down the page belongs to somebody else.
- Clusters are client walls. Three or more logo images packed into a short span of markup is a portfolio strip. None of them belong to the site.
- Name match. The brand or domain appearing in the filename or alt text is the strongest positive signal available.
A candidate that satisfies none of those should be skipped rather than used. No result beats a wrong one.
3. Social icons are named like logos
Every social, payment and app-store badge ships as pinterest-logo.svg, facebook-logo.png, visa-logo.svg. Any filter asking "does the filename say logo" accepts all of them. Exclude known third-party marks by name.
The trap inside the trap: match the filename, not the whole URL. A logo served from squarespace-cdn.com or an industry directory CDN still belongs to the shop. The hostname tells you who serves the file. Only the filename tells you what is in it.
4. A validity check is not a correctness check
We built an end-to-end test that opened each result, downloaded the file and verified the PDF structure, including that every cross-reference offset landed on its object. It passed every time. It was answering "is this file valid", while the question that mattered was "is this the right logo". Those are not the same question, and only looking at the output answers the second one.
What it cost
At roughly a cent per raster conversion, 10,024 logos came to about $127. Two adjustments cut that dramatically for anyone repeating it:
- Skip what is already vector. 13% of ours, at zero cost.
- Convert on demand, not up front. Fetching a page and choosing an image is free. Only the conversion is billed. If the output is only needed when someone actually opens it, convert on first view and cache the result. On our workload that is the difference between paying for ten thousand conversions and paying for a few hundred.
The second point is the one we got wrong first, and it is worth being blunt about: we paid for ten thousand conversions before knowing how many would ever be looked at.
Doing this yourself
The VectoSolve API exposes the same conversion this benchmark used. A minimal batch loop:
const res = await fetch('https://vectosolve.com/api/v1/vectorize', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.VECTOSOLVE_API_KEY}` },
body: form, // multipart, field name: file
})
const { svg } = await res.json()
Machine formats come out of the same source file: DXF for laser and CNC, DST, PES and JEF for embroidery, G-code, EPS and AI. If you are converting logos in bulk you almost certainly need one of those next, and converting twice is the mistake after this one.
The short version
Bulk vectorization is not hard to make fast. A bounded pool and skipping work you do not need to do covers most of it. What is hard is making sure the thing you converted is the thing you meant to convert, and no amount of green test output will tell you that. Look at a sample of the real output, and look at the batch that is about to go out rather than a random one.