Next.js · B2B food production
MAMA Food
A three-language lead-generation site, set up to measure and rank
MAMA Food makes ice-cream bases, mixes and sorbets for ice-cream shops and producers. Its Next.js site, in Polish, English and Greek, collects inquiries and sample requests. I took over the existing site and added what it needed to measure leads and rank in the right language: Consent Mode v2, a reliable lead event, the language and canonical setup, and Open Graph images for every page.
- Role
- Developer extending an existing site (29 of 85 commits)
- Period
- Apr - Sep 2026
- Stack
- Next.js 16
- React 19
- TypeScript
- Tailwind CSS 4
- GTM
- Consent Mode v2
- next/og
- sharp
- Live site
- mama-food.pl(opens in a new tab)


- languages: PL, EN, EL
- 3
- URLs in the sitemap with hreflang
- 18
- Open Graph image per page
- ~600 → ~90 KB
Context
The site is not a store: the only conversion is an inquiry or sample form. That makes the lead event and the consent setup the core of the analytics.
The site already existed in Next.js. My work was the part between the code and the business: what Google indexes, what GA4 counts and what a shared link looks like.
What I did
- Google Tag Manager with Consent Mode v2, denied by default, and a cookie banner with a real category panel and a settings link in the footer
- Page language pushed to the dataLayer, so reports can be split by language
- A generate_lead event that fires only after a successful send, with a guard against double submits
- Polish as the default language, with canonical, hreflang and x-default fixed, plus sitemap and robots.txt
- Open Graph images generated per page and per language with next/og and sharp, saved as JPG
- Deterministic build ID, icons, web manifest and Search Console verification
Hard parts and how I solved them
Problem
Googlebot sends no Accept-Language header, so it was redirected to the English version, and canonical URLs pointed to an old domain that no longer worked.
Solution
Polish became the default for requests without a language preference, and canonical, hreflang and x-default now point to the live addresses.
Problem
React 19 does not allow script tags directly under <html>, which is where the consent and GTM snippets used to sit.
Solution
Both moved into <body>, and a small inline ES5 script restores the saved consent before gtm.js loads, so tags never fire before the visitor's choice is known.
Problem
GTM's built-in form trigger counted a lead even for an empty, invalid form.
Solution
A custom generate_lead event pushed only after the server confirms the send, tested in 6 scenarios.
Results
- 18 URLs (6 pages × 3 languages) in the sitemap, with hreflang
- Open Graph images 81-92 KB as JPG instead of 548-630 KB as PNG; 18 of 18 checked
- Leads counted only for messages that were actually sent
Screens
Swipe or use the buttons to browse the screens.
Want this kind of work on your team?
I'm happy to walk you through any of these projects in more detail.
Get in touch


