E-commerce · Services · Local SEO
Rolo ElectronicsStore, blog and service pages with an admin panel and measured SEO
Complete platform for a security-electronics business in Connecticut and New York: online store, blog, service and city pages, inspection booking, and an admin panel with first-party analytics, Search Console and GA4.
Technologies
- Next.js 16
- React 19
- TypeScript
- Supabase (PostgreSQL + Auth + RLS)
- Tailwind CSS v4
- shadcn/ui
- next-intl
- Recharts
- TipTap
- Resend
- SheetJS
- Search Console API
- GA4 Data API
136
sitemap URLs
35
local pages
30
blog articles
~58
products
18
admin modules
3
languages
My role
Full stack development of the platform - store, content and admin panel - plus the SEO/GEO strategy and all the measurement instrumentation. Delivered through NM Tech Studio and improved continuously since.
The problem
The business sold security equipment and also installed it, but those are bought in completely different ways: a product goes in a cart, an installation gets quoted and often starts with an on-site inspection. On top of that sat a more expensive problem: there was no way to tell which page produced calls. Forms died in loose emails, not a single conversion event existed, and the site was competing against itself in several cities.
What I built
- Online store with a ~58-product catalogue, filters by category, brand and price range, product detail pages, cart and checkout for both guests and registered users.
- A 30-article blog organised by topic: installation costs, equipment comparisons, city guides and local alarm-permit rules.
- Service pages split by intent: cameras, alarms, smart home, networking, multi-room audio and access control.
- 35 local city pages - Greenwich, Stamford, Norwalk, Port Chester, Queens, White Plains, Rye and the rest of the area - each with its own FAQ, nearby areas and links to its neighbours.
- An inspection booking module with business hours, blocked dates and time slots that fill up as they are taken.
- An admin panel with 18 modules, grouped into overview, commerce, catalogue, operations and system.
- First-party analytics - sessions, visitors, page views, traffic sources, countries, contact clicks per channel - next to Search Console and GA4 data inside the same panel.
- An automated weekly email digest: sessions, visitors, messages, appointments, orders, revenue and the top searches, pages and products, all compared against the previous week.
- A CMS for navigation, section images and content pages, so the client changes copy without touching code.
- A three-language site (Spanish, English and French) with roles and permissions for the internal team.
SEO driven by data, not by intuition
The strategy came out of auditing a three-month Search Console export - 98 pages, 217 clicks, 54,845 impressions - cross-read with GA4. Every cluster with real impressions got one owning URL, and everything else started linking into it instead of competing with it.
- Clusters prioritised by impressions and weighted position: Port Chester alarms, Greenwich smart home, Stamford and Queens cameras, Sonos audio.
- Exactly one H1 per page: /services rendered two and /products had none above its filters.
- A keyword-owner map and internal linking to end the cannibalisation between pages for the same city.
- Every product links to the service page that owns its intent: a model query goes to the product page, an installation query to the service page.
- GA4 events where none existed: phone click, booking click, form submit and confirmed lead.
- gclid, gbraid, wbraid, msclkid, fbclid and every utm_* captured on the session's first page, so a lead converting three pages deep still carries the click that brought it.
Booking that ends with a technician on site
The appointment form is not a loose email: it coordinates the customer, the calendar and the field team in one operation.
- The visitor picks a service type, a day and a time slot; the calendar honours business hours, blocked dates and slots that are already taken.
- Confirming sends two emails. The customer gets their appointment summary with a link to add it to Google Calendar.
- The team gets the alert with name, phone, address, service type and notes: exactly what the technician needs to go inspect the property and come back with a real quote.
- The appointment is stored in the database, the slot is closed, and it shows up in the panel as pending, confirmed or cancelled.
- The same request is copied into the lead inbox with its source and raises an in-app notification.
- Business hours, service types and blocked dates are configured from the panel, without touching code.
The content does the heavy lifting
The store on its own did not bring enquiries: the articles and the service and city pages do, because they answer what people search before deciding who to call.
- 30 long articles on real queries: installation costs in Westchester and Greenwich, NVR vs cloud, Ring vs Hikvision, hidden cabling in finished homes, alarm permits, Wi-Fi 7 and cameras with no monthly fee.
- 35 city pages, each with its own FAQ, its areas and its links to neighbouring towns.
- Service pages by intent, kept separate from the catalogue, so an installation search never lands on a product page.
- The visible FAQs and their JSON-LD come from the same data array, so what is read and what is marked up can never disagree.
GEO: making AI search able to cite it too
Beyond classic SEO, the site is set up so generative engines can read it, understand it and cite it with correct facts.
- llms.txt and llms-full.txt generated from the same data modules that render the site, so they never drift from the published content.
- robots.txt explicitly allows GPTBot, ChatGPT-User, PerplexityBot, ClaudeBot, anthropic-ai and Google-Extended, and blocks CCBot, which only harvests for training.
- Deep structured data: LocalBusiness with its service areas, Service, Product with its Offer, FAQPage, BreadcrumbList, Organization and Person on the articles.
- A 136-URL sitemap with no query strings and real update dates rather than a touched timestamp.
The admin panel
Each module covers one part of the day-to-day operation, without leaving the panel.
Overview
Sales, pending orders, appointments awaiting confirmation and the latest leads on one landing screen.
Analytics
First-party metrics, Search Console and GA4 in the same panel, over 7 to 90-day windows and compared against the previous period.
Visitors
A visit-by-visit log with source, country and pages viewed, plus a switch to exclude bots from the count.
Products
Create, edit and archive with Excel import and export, images, prices and publication status.
Inventory
Stock handled separately from the catalogue, with reversible deletion and restore.
Orders
Order management and status changes, with a pending counter in the navigation.
Customers
Buyer list with their history, addresses and associated orders.
Categories & brands
The catalogue taxonomy, which feeds the storefront filters and the internal linking.
Coupons
Discounts with their usage rules, applied at checkout.
Leads
One unified inbox: every opportunity arrives tagged with its source - booking, contact or campaign.
Appointments
Requests marked pending, confirmed or cancelled, plus the configuration of business hours, service types and blocked dates.
Contacts
Messages from the public form, with their reply and follow-up.
Shipping & payments
Shipping zones and enabled payment methods, cash and bank transfer included.
CMS
Header navigation, per-section images and content pages, editable without a deploy.
Reviews
Moderation of real product reviews - the only ones displayed and the only ones marked up as structured data.
Settings
Site name, logo, colours and SEO metadata, all managed from the panel.
Users & roles
Role-based access to the panel, with routes protected at the middleware layer.
Notifications
In-app alerts when an appointment or an order arrives, plus the weekly digest that goes out by email.
Technical decisions
- Two separate journeys on one platform: straight checkout for products, a quote or a booking for installations. Forcing everything through a cart would have broken the services side.
- Every lead - booking, contact form and campaign forms - lands in one table tagged with its source. Before that each form ended in a different inbox and nobody knew how many opportunities came in per month.
- The appointment is written to the database before the visitor gets a response, so the slot is taken and two people cannot book the same hour.
- GA4 fires generate_lead only after a confirmed server success, never optimistically: a form that fails cannot be counted as a lead.
- Search Console and GA4 are queried through their APIs from inside the panel, over 7, 14, 30 and 90-day windows, so the client sees queries, impressions, CTR and position without opening another tool.
- I removed the synthetic ratings and reviews the catalogue generated from each product id and emitted as Review JSON-LD on every product page. That is fabricated review markup - against Google's policy - and stars now appear only when a real review exists.
- Titles and H1s rewritten against a ~60-character budget, built from the clusters that already had impressions instead of what sounded good: several local pages ran 78-84 characters and were being truncated in the results page.
- Next.js with server rendering, so product pages, articles and service pages are crawlable and citable without depending on JavaScript.
Challenges
- Combining product sales and service sales without the site feeling like two sites glued together.
- Serving a household customer and a corporate one at once, with different expectations and budgets.
- Killing the cannibalisation between the Greenwich pages, which were competing with each other for the same query: each intent had to get one owning URL and everything else had to link into it.
- Writing 30 articles and 35 city pages without falling into a repeated template and without inventing business facts: wherever the client could not verify a number - project counts, certifications, response times - the section simply was not published.
- Differentiating heavily templated product pages, which carried a 0.10% CTR in the rich result, without leaning on data that did not exist.
Result
The site now works as a store, a blog and a network of local pages, with a single lead inbox and a panel that shows which query brings impressions and which page brings calls. The business reports having tripled its service requests since SEO became continuous work, with people arriving by phone, form, booking and WhatsApp. The initial audit - 98 pages, 217 clicks and 54,845 impressions over three months - stands as the baseline every iteration is compared against.
