Portfolio / SEO, GEO and AEO for e-commerce
Specialty coffee, readable by Google and by AI.
Broo Café sells specialty coffee from Antioquia online, out of Medellín. The store already existed and already sold; what it didn't do was explain itself. It still carried leftovers from a beauty-store theme demo, its product pages had no H1 and its schema contradicted itself. We audited it, cleaned it up in phases and measured every change, rebuilt its structured data from WooCommerce, started a sourced editorial program and took it into English with a checkout of its own.

01The challenge
A coffee store that talked like a template.
Broo's site was built on a commercial theme whose demo is a beauty store, and the demo never quite left. The footer, present on 21 pages, linked to “face”, “body” and “hair” categories that didn't exist, to “Gift cards” that led to the export page and to a “Return” link that opened the terms. The social icons pointed to the theme vendor's account.
What you couldn't see was worse. No product page had an H1, and of the 22 pages that returned 200 only 1 had exactly one: 11 had two, because Elementor split each title across two widgets. The schema declared a coffee shop with opening hours for a store that only sells online, put articles and authors on pages that weren't articles, and marked up 10 FAQ entries where 15 were on the page.
And the site promised things the store didn't do: subscriptions, with an inactive plugin and a URL that returned 404; international shipping by DHL, when it only ships within Colombia; and a payment gateway in the terms other than Mercado Pago, which is the one that actually charges. Merchant Center, meanwhile, had the wrong shipping rates, no return policy and the cold brew flagged as an alcoholic beverage.
What needed solving
- 01Remove the demo leftovers without touching the design
- 02One H1 per URL, product pages included
- 03Schema that told the truth about the business
- 04Site promises that match real operations
- 05Merchant Center with real shipping and returns
- 06A base answer engines could actually cite
Our role
Technical audit, on-page SEO, structured data, GEO and AEO, a custom mu-plugin, Merchant Center fixes, editorial strategy and production, the English version and its checkout, and article typography.
02The method
Audit, change in phases, measure again.
Don't make up data. Not in the schema, not in the copy.
The work ran on the live store, with the owner's explicit approval for each phase. Before every phase, a full database backup with its row count checked against the live database; in the changelog, every line records what was there, what replaced it and how to undo it.
Our code lives in one place, a must-use plugin, with no edits to the theme or the plugins. Each module loads in isolation, and a single empty file switches the whole package off if something breaks. The editorial rule applied to data too: rating, reviews, altitude, farm or certifications stay as placeholders until the owner confirms them. Review markup only appears if real, approved reviews exist.
Every phase closed with the same crawler it opened with: our own scripts that walk the sitemaps, check H1s, title and description lengths, canonicals, robots, alt text, JSON-LD types and broken links, and leave a before report and an after report.
A backup per phaseA rollback per changeMeasured before and after
03Before and after
What the crawl measured at the end of each phase.
Figures from our crawl reports of 28 September 2026, before and after each phase. They measure technical health, not traffic: they describe the site Google and answer engines now find.
- 5 → 0
- broken internal links
- 2 → 0
- duplicate titles across product pages
- 1 → 25
- pages with a single H1 (of 22, then 25, crawled pages returning 200)
- 10 → 15
- FAQ entries in the schema, of 15 on the page
- 0
- validation errors across 21 JSON-LD snapshots
- 13
- 301 redirects from normalizing slugs and categories
04The architecture
Four zones, one entity.
There was no need to invent sections. Each page needed a clear job and a schema type that said so. Breadcrumbs follow the same order across the site: Home, Shop, category, product; or Home, Blog, category, article.
7 products, 3 categories.
Specialty coffee, Cold brew, Coffee cocktails. Slugs normalized so name, weight and URL say the same thing, with 301s from the old ones. Shop and categories as CollectionPage; each product page as an ItemPage with its Product.
Story, difference and export.
Our story and Our difference as AboutPage. Green coffee export by quote as a service with its own offer catalog, kept apart from consumer sales, which are domestic only.
A blog that links to the shop.
Three categories: brewing, cold brew and iced coffee, and origin and processing. Each article links to its pillar, its siblings and products by SKU; each product page lists the articles that reference it.
A mirror under /en/.
Pages, product pages, articles, cart, checkout and account in English, with hreflang es, en and x-default. Built for the green coffee importer, the specialty fan abroad and the visitor buying from inside Colombia.
05The store
The same design, now properly structured.

The home page headline wasn't an H1. Now it is, in the same Mattone at the same size: the change doesn't show, it reads in the code.

An H1 that carries the search intent, “Tienda de café de especialidad”, instead of “Archives: Tienda”. Product titles in the grid moved down from h2 to h3.

Full breadcrumbs, a single H1 without SEO suffixes and a required grind choice before buying. Behind it, a Product with brand, SKU, attributes and an offer in Colombian pesos.

The same fixes on mobile: one H1 per screen and the same hierarchy as on desktop.

The B2B line, green coffee in vacuum bags by quote, with its own service schema. Consumer sales no longer promise international shipping.

The English home page, localized by hand from a glossary and a localization brief, not by an automatic translation plugin.
06GEO and AEO
From the real catalog to the answer engine.
An answer engine cites what it can read without ambiguity. That's why the schema and the llms.txt weren't written by hand: they're generated from what WooCommerce already knows, and they change when the store does.
WooCommerce
Products and zonesbroo-seo
Custom mu-pluginJSON-LD
One graph/llms.txt
Catalog as textGoogle
Search and MerchantAI engines
Cited answers
- 01
One entity
A single OnlineStore “Broo Café” with a Medellín address, contact point, social profiles and its return policy replaces the coffee shop with opening hours that never existed.
- 02
Shipping from the real zones
OfferShippingDetails is built from WooCommerce's shipping zones: each active rate becomes a region with its handling and transit times. Nothing is hard-coded.
- 03
A complete product
Product with brand, SKU, gallery and attributes; an Offer in Colombian pesos with price validity, shipping details and a MerchantReturnPolicy.
- 04
FAQ equal to the page
The FAQPage is built by reading the accordions in the Elementor document. Edit a question and the schema changes with it: 15 on the page, 15 marked up.
- 05
A live llms.txt
A text file generated on every request with the products, their COP price, availability and attributes, the categories, shipping, returns, payments and key pages, plus an English section.
- 06
Citable articles
Each article emits a BlogPosting with its sources in the citation property and a FAQPage whose text is identical to the questions on the page.
This is infrastructure, not a result. As of the audit, the brand isn't yet cited in AI answers; the groundwork for it is in place.
07Citable content
The answer first, then the context.

Every article opens with a 40 to 60-word answer and its source: here, the cold brew ratio and steeping time from the National Coffee Association. Below it, a table of contents with the H2s written as questions.

Five FAQs per article, with the same text on the page and in the FAQPage. A 760 px reading column and 18 px body text.

The 15 questions on orders, shipping and products are the source of the site's FAQPage. Before, the schema marked up only 10.

The catalog as a model reads it: each product with price, availability, origin, process, roast, weight and altitude, followed by shipping, returns and payments. Served as plain text and kept out of Google's index.
08The code
One mu-plugin, seven modules, 1,831 lines.
Everything custom lives in broo-seo, a must-use plugin that doesn't depend on the theme and loads before any regular plugin. Each module has one job, loads in isolation and can be switched off without touching the rest.
One H1 per URL.
The first fragment of a split title stays the H1 and the rest is appended for screen readers; the second widget becomes a div with the same look. Loop titles drop to h3 and the “Archives:” prefix goes away.
The business graph.
Entity, page types, Product, Offer, shipping from the zones, returns and the FAQ read from Elementor. It strips images that came from the demo's domain.
Breadcrumbs with context.
Rank Math's, with Shop or Blog inserted in the path and the same styling WooCommerce's used to have.
A catalog for models.
The /llms.txt generated from WooCommerce, as plain text with noindex. It replaces Rank Math's own module, which was switched off.
The editorial machinery.
Article schema with sources, quick-answer styling, cross-links with products, redirects when an article is replaced and a cache purge when a scheduled post goes live.
English that can buy.
English templates and menus, localized links, hreflang, the language switcher and the English cart and checkout.
No English on the Spanish site.
Translations for theme and plugin strings that showed up in English on the Spanish site, plus the cookie banner copy.
09The editorial program
32 articles, each with a source.
The blog was planned in two batches. The first, 12 articles approved with their keywords, was scheduled for Mondays and Wednesdays at 7:00 from 29 September to 5 November 2026: brewing methods, cold brew, French press, processing, whole bean or ground, V60, Chemex, AeroPress, moka pot, coffee cocktails. The second, 20 articles, came out of a trend research pass for Q4 2026 and started publishing on 26 October.
Every article follows the same template: a title of up to 60 characters, a description of 140 to 160, question-form H2s, five FAQs and at least one primary source. The 12 in the first batch cite 38 sources, every one checked as returning 200 before publishing: the SCA, the National Coffee Association, a Scientific Reports study, the Hario, Chemex, AeroPress and Bialetti manuals, Colombia's coffee growers' federation, Cenicafé and World Coffee Research, among others. In the trend batch, every data point carries its source and the weak ones were flagged “do not use”.
The author is “Equipo Broo Café”, with no invented credentials. Images are free Unsplash photos credited to the photographer. A link to an article that isn't out yet renders as plain text until the target goes live, and the cache is purged on publish so links and the product-page blocks update on their own.
Every article's template
- 01A 40 to 60-word quick answer, with its source
- 02Table of contents
- 03H2s written as questions
- 04Five FAQs, also in the schema
- 05Primary sources on the page and in the schema
- 06Links to the pillar, the siblings and the products
10The English version
Buying in English without duplicating the store.
The English version runs on Polylang: 11 pages, all 7 product pages, the published and scheduled articles, 12 Elementor templates, 5 menus and 79 alt texts served only on English pages. The copy was localized by hand from source files, with a glossary and a per-language SEO brief.
The interesting problem was the cart. Duplicating the products in English would have split inventory, orders, reports and the Merchant Center feed in two. The English product page is purchasable, with its own English grind options, but on add-to-cart the item is swapped for its Spanish twin. Options are stored in Spanish on the order and shown in English in the cart and checkout. Stock, orders and reports still live on a single product.
Cart, checkout and account have their own pages under /en/, and WooCommerce's AJAX requests are routed there too. Shipping and payment labels are translated only for the English-speaking customer; the payment logic was left alone and order emails stay in Spanish. Before release, a review caught that the first “Buy now” button added coffee without the required grind. It was fixed before a single order went through it.
The one exception
Payments, taxes, shipping and prices were out of scope from day one. The English checkout was the single approved exception, and only for routing and language.
11The design
We didn't redesign the brand. We made it readable.
The visual identity is the one Broo already had: the orange, sand and black of the Elementor kit, the navy of the labels, Mattone for headlines and Kanit for reading. We didn't change a single layout. The H1 fixes were built to keep exactly the same look: a visitor doesn't notice the difference, a crawler does.
Where we did step in was article reading. The article H1 ran past 60 px and broke into three lines; it now scales between 44 and 28 px with an 880 px max width. Body H2s went from 60 px to a 34 to 24 px scale. Body text went from 16 px at around 180 characters per line to 18 px with 1.7 line height in a 760 px column. Inline images are capped, tables scroll horizontally and the author box sits in two columns.
12The client's visual system
Orange, sand and navy: the brand as it was.
Accent · Active nav · Quick answer
- HEX
- #FF6A00
- RGB
- 255 · 106 · 0
Logo · Pouch labels
- HEX
- #062149
- RGB
- 6 · 33 · 73
Headlines · Buttons
- HEX
- #000000
- RGB
- 0 · 0 · 0
Shop and blog background
- HEX
- #F5F3F1
- RGB
- 245 · 243 · 241
Hero card
- HEX
- #FAF9F8
- RGB
- 250 · 249 · 248
Borders · Dividers
- HEX
- #DCD6CC
- RGB
- 220 · 214 · 204
Secondary text
- HEX
- #5E5E5E
- RGB
- 94 · 94 · 94
13Article typography
A wide display face, a sans that's easy to read.
Mattone
Aa Bb Cc — 0123456789
Single weight, self-hosted
Kanit
Aa Bb Cc — 0123456789
Regular 400 · Medium 500
Kanit · small caps
Aa Bb Cc — 0123456789
Medium 500
What cold brew is and how to make it at home
44 → 28 px · max 880 pxHow do you make cold brew at home?
34 → 24 pxIt's hot, you want coffee and a fresh cup doesn't appeal. There's no barista secret to cold brew: there's time.
18 px · 1.7 · 760 px columnHome / Blog / Cold brew and iced coffee
16 px · uppercase14Where it stands
The foundation is in. Measurement is just starting.
On 24 October 2026 we ran a read-only audit with Search Console data, live SERP checks, backlinks, Lighthouse and AI answer mentions. Its conclusion was the one we expected: the bottleneck is no longer technical. The site crawls clean, the schema validates and Google already shows the product pages with prices in results. The window for measuring traffic and sales is only just opening, and we won't get ahead of numbers that don't exist yet.
What's missing gets said too. The brand shares its name with cafés in other countries and needs entity work. The product pages have no reviews yet. The blog links to the shop too little, and the blog index links to no product at all. The automation that replaces old articles left one URL undrafted, and it's still on the list. The next steps the audit recommended (category pages for “café en grano” and “café molido”, brand entity, reviews and authority) are recommendations, not delivered work.
Delivered
- 01Demo leftovers gone, design unchanged
- 02One H1 per URL and unique titles
- 03A JSON-LD graph from real WooCommerce data
- 04A FAQPage read from the page itself
- 05A live, generated llms.txt
- 06Merchant Center with real shipping and returns
- 0732 sourced articles, scheduled
- 08An English version with its own cart and checkout
15The value
What changes when the store tells the truth.
What the site promises, the store delivers.
Before, the site promised subscriptions, international shipping and a payment gateway that didn't exist, and told Google it was a coffee shop with opening hours. Now every promise matches the operation, and every data point Google, Merchant Center or a language model reads comes from the same source the store uses to sell.
It's a foundation that doesn't rely on a trick: if a shipping rate, an FAQ or a price changes tomorrow, the schema and the llms.txt change with it.
Real dataOur own measurementBilingual
beleafdesign
Does your store tell Google what it tells your customers?
If you sell on WooCommerce, we'll review what Google, Merchant Center and answer engines find on your site today, and what they should find. Measured before and after.
Let's talk about your project