Skip to main content

Command Palette

Search for a command to run...

I generated 200 Pinterest images from Search Console data — and found I'd been targeting the wrong keywords in three languages

Updated
5 min readView as Markdown
O
Fullstack developer based in Lithuania. I build and run small multilingual side projects — currently tarot-magic.com, a tarot reference in four languages: React, Supabase, four locales, 312 pages. I write about the unglamorous half of that: a prerender that forgot its links, an analytics script that ranked keywords for the wrong language, and the checks I should have run a month earlier.

My site is a tarot reference in four languages: English, Russian, Ukrainian and French. 78 cards, one page per card per locale, 312 card pages in total.

It ranks, sort of. Over its first 38 days Google gave it 10,820 impressions and 53 clicks — average position 23.9, which is page three. So I did the obvious thing for a site with no budget and a lot of images: Pinterest.

Pinterest is a search engine, not a feed. That means I didn't need to guess what to post. I already had a file that said exactly what people were searching for: the Search Console export.

The script

Nothing clever. A Python script that:

  1. reads pages.csv from the GSC export and ranks cards by impressions,

  2. pulls the card artwork and card data off my own site,

  3. composes a 1000×1500 pin in Pillow — artwork, card name, keywords, my domain,

  4. writes it to pins/cards/<lang>/<slug>.png, skipping anything already published.

Roughly 200 lines. It produced the whole queue for all four languages in one run, and re-running it after a fresh GSC export just re-sorts the queue. The part I'm actually pleased with is that it skips what's already out — the "what do I post today" question answers itself.

The bug

The ranking step read pages.csv, summed impressions per card across the whole site, and used that single ordering for every language.

That felt right when I wrote it. A card is a card; if Ten of Cups is popular, it's popular. And for a month I published from that list.

Here is what the data actually says when you split it by locale:

Locale Top card Impressions
Russian Ten of Cups 270
Ukrainian Six of Wands 308
English Four of Wands 158
French The Magician 19

Four locales, four completely different answers. Not "similar lists in a different order" — different cards.

The aggregate had been dominated by whichever locale happened to be loudest, and I was posting that locale's cards to all four boards. Concretely: two of the three pins on my Russian board — Three of Wands and Knight of Pentacles — were there because of Ukrainian demand. In Russian those two cards had 20 and 22 impressions. I had spent pins on the fourth and fifth best guess while the actual top of the list sat unpublished.

The Ukrainian board, by accident, was perfect. Same list, right language.

Why I didn't catch it

Because the output looked fine. Every pin was a real card, correctly rendered, in the correct language, linking to the correct localized URL. Nothing was broken. Nothing 404'd. The images were good.

The only thing wrong was the order, and order is invisible unless you go back to the source data and ask "why this card and not that one?" I had validated that the script worked. I had not validated that it was answering the question I thought it was asking.

This is the same shape as a bug I wrote about last week — the site was prerendering text for crawlers but no links, and everything looked fine there too. Both times the check I skipped was cheap and the thing it would have caught ran for a month.

The fix, and the rule I wrote down

The fix was ten lines: group by URL prefix (/ru/, /uk/, /fr/, root for English) before ranking, and emit one queue per locale.

The rule I wrote into the project's notes, so future-me doesn't undo it:

Demand is counted per locale, separately. Never reuse one locale's card order for another. If a locale has little data, fill it in the same format as the others — don't skip it and don't borrow.

That last sentence matters for French. French is my weakest locale by far — 394 impressions total, average position 48, and a "top card" with 19 impressions. The temptation is to either skip it or paste the English list in. Both are wrong: 19 impressions is still a real signal about what French speakers search for, and it happens to be a different set of cards. French searches lean toward the Major Arcana — The Magician, The Tower, The World — where Russian and Ukrainian searches are almost entirely Minor Arcana. Pasting the English list over it would have produced pins for cards nobody in that language looks for.

Where it stands

56 pins published across four boards, queue regenerated per locale, one command to record a publication and move the file to an archive folder so the "what's left" list stays honest.

Traffic results: too early, and I'd rather say that than make a number up. Pinterest takes weeks to distribute new pins and my account is a month old. What I can say is that the queue is now sorted by what people actually search for in each language, which it wasn't before, and that cost me about ten lines of code and one uncomfortable afternoon with a CSV.

If you run a multilingual site and you're prioritizing content from analytics: check whether your ranking is grouped by locale. Mine wasn't, it looked completely fine, and it was wrong in three languages out of four.


The site is tarot-magic.com — tarot card meanings in four languages.