The challenge
East Coast Solar designs, engineers, permits and installs solar across Massachusetts, and does all four in-house rather than subcontracting. That is a genuine differentiator in a market full of sales outfits that hand the actual work to whoever is cheapest that month. Almost none of it reached anybody searching.
The Squarespace site produced roughly one estimate request a month. Its estimate form was worse than that number suggests: it simulated a submission and discarded the lead. Hero imagery shipped as CSS background images at 971KB, bypassing any optimizer. Page titles rendered the brand twice. There was no analytics property, so nothing about any of this was visible.
The timing made it urgent rather than merely unfortunate. The federal 30% residential tax credit, worth roughly $9,000 on a $30,000 system, was eliminated at the end of 2025. Passive, incentive-driven demand went with it. When buyers stop arriving because the math is obvious, the ones still shopping are researching, and research happens in search results and increasingly inside AI assistants. A company that is invisible in both has no pipeline.
There was a structural problem underneath the visible one. The domain reads eastcoast.solar, implying coverage from Maine to Florida, while the business is Worcester and Central Massachusetts. And their Google Business Profile is a hidden-address service-area listing that does not surface in the Places API by exact name, while Worcester competitors do. Every geographic signal the site could send needed to point somewhere the profile itself was not pointing.
The solution
We replaced the Squarespace site with a custom Next.js build: about 40 route groups expanding into roughly 70 pages, including 35 town service-area pages, residential and commercial service trees, a portfolio, an incentives library and a savings calculator.
The calculator is the piece that changed the shape of the funnel. A visitor enters an address and a monthly bill and gets back a modeled system size, annual production, 25-year savings and CO2 offset, computed against Google's Solar API. It is a reason to hand over an address that has nothing to do with wanting a salesperson to call, which is the opposite of how a contact form works. Results are not email-gated; the client rejected that outright and asked for a "speak to a professional" prompt beside the numbers instead, which was the right call.
The incentives content was built to be the most useful page on the Massachusetts solar internet: SMART, net metering, the state credit, the federal ITC's actual status, MACRS depreciation and Class I RECs, each explained in a self-contained passage rather than scattered across a sales narrative.
Then the part that took the longest. The 35 town pages launched sharing about half their text, because only a description and a short local paragraph varied between them. That is the shape Google's doorway-page handling exists to suppress, and the pages behaved accordingly: high impressions, position 27 to 35, almost no clicks.
Fixing it meant actually researching thirty-five towns. Each page now carries housing stock an installer would recognize (Framingham's Campanelli ranches have wide, low-pitched, uninterrupted roof planes and are among the easiest installs in MetroWest; Saxonville is Victorians with steep cut-up roofs), the real permitting path (which department, the OpenGov portal, whether a local historic district adopted under MGL Chapter 40C puts panel placement in front of a commission first), utility specifics, real municipal programs with the date each figure was confirmed, and town-specific questions with real answers. Every factual claim traces to a URL recorded in that town's sources array, and the citations render on the page.
Across all 528 page pairs, 7-gram text uniqueness went from 50.7% to 78.3%. The worst pair went from 57.0% to 26.8%, and no pair finished above 40%. Median page length went from 725 words to 1,374.
AI architecture
The site was built on the assumption that a growing share of its readers would be machines summarizing it for somebody else, and that those machines need different things than Googlebot does.
FAQ answers render in the server HTML. The accordions on every service page are force-mounted and collapsed with CSS rather than unmounted, so the answer text is present in the document a crawler receives instead of appearing only after a click that no crawler performs. Each set is backed by FAQPage JSON-LD. An answer an assistant cannot read is an answer that cannot be quoted.
llms.txt is generated from the same constants and data modules the pages render from, not maintained by hand. It had been a static file, and it drifted: it advertised "15+ reviews" while the LocalBusiness schema on every page said 14. Assistants read both the markup and that file, so a disagreement between them is a credibility problem on precisely the surface the file exists to serve. Deriving it from shared data means the two can no longer disagree.
The structured data was made honest rather than flattering. The self-serving aggregateRating was removed from LocalBusiness. Review nodes on /reviews reference the organization by @id instead of declaring a second LocalBusiness entity, so the page resolves to one entity with one rating rather than two competing ones. Review counts were aligned to what Google publicly shows.
Accuracy got enforced at the data layer, because an assistant that quotes a wrong claim propagates it. The town template had promised SMART eligibility to every town; SMART is limited to the investor-owned utilities, which made it wrong for Shrewsbury, Concord and Hudson, all served by municipal light plants. It now branches on utility. Federal ITC status was consolidated to one place so no two pages could describe it differently. The rule written into the data files is to omit a field rather than guess at it, and to date any figure that can change.
AI referral traffic is tracked as its own channel in GA4. That is the only reason there is a number to report at all: most sites cannot distinguish an assistant-referred visit from direct traffic, so the channel is invisible to them by default. IndexNow submits new and changed pages on deploy rather than waiting to be crawled.
Performance was treated as part of this rather than separate from it. The h1 animated in from opacity zero, which meant the server-rendered headline, usually the LCP element, was invisible until JavaScript hydrated. Hero backgrounds shipped as unoptimized CSS images. Both were fixed: hero images now go through the optimizer at roughly 50KB of AVIF instead of 971KB of JPEG, and the headline animates from a stylesheet keyframe that runs at parse. Throttled mobile LCP on /residential went from 9,152ms to 1,828ms, /portfolio from 7,840ms to 1,340ms, and the homepage from 7.3s to 4.2s with FCP from 2.9s to 0.9s.
The results
In the first 58 days after launch, the site produced 18 estimate requests from 18 distinct users, against roughly one a month from the site it replaced. That is a visitor-to-lead conversion rate of 4.0%.
Traffic barely moved. Sessions were up about 7% against the matched window a year earlier, and engagement improved modestly, with pages per visit going from 1.67 to 1.93. Almost all of the lead gain came from converting the visitors they already had, not from finding new ones. For a business whose category just lost its federal subsidy, that distinction matters: the improvement did not depend on demand recovering.
The search footprint was built from essentially nothing: 18,708 impressions across 967 distinct queries and 50 pages. Seven sessions arrived through the AI Assistant channel, and the AI referral event fired twice. Seven is a small number and worth naming as one. The point is not the volume; it is that the channel is visible at all, and that a competitor without the same instrumentation is looking at the same visits filed under direct traffic.
What has not happened is ranking. Average position sits at 26.9, page three, and it was flat across all eight weeks measured. There were 128 clicks in 58 days, 48 of them on the brand term. The visibility exists and has not yet converted into traffic.
The near-term shape is legible, though. MetroWest sits at position 8.6, Greater Boston at 11.9, Framingham at 16.5. Those are town pages, the ones that got the depth work, and they are the realistic wins in the next ninety days rather than the statewide head terms sitting on page three. The brand term averages 6.8, meaning the company does not reliably own its own name, which points squarely back at the Business Profile rather than at anything on the site.
