Automated Website and Mobile Application Testing Engine (Fully AI-Enabled)
An autonomous synthetic testing agent that navigates complex web and React Native mobile user flows, self-heals broken locators, and generates regression test suites without manual scripting.
85%
Reduction in test maintenance overhead
Self-Healing
Dynamic locator resolution on DOM changes
Cross-Platform
Next.js Web, iOS & Android React Native
10x
Faster regression test execution cycles
Deterministic scoring with AI interpretation layered on top
The system scores any public landing page across six categories using 52 deterministic checks, then layers AI interpretation on top.
It was built security-first: the backend never fetches user-supplied URLs, every plan limit is enforced server-side, and the extension collects page structure without ever touching form values, cookies or browsing history.
| Product | AdLanding Inspector — landing-page audits for paid search |
| Type | Chrome extension (Manifest V3) + SaaS web app and API |
| Core stack | TypeScript, Next.js 16, React 19, Supabase (Postgres), Stripe, Google Gemini |
| Scale | ~21,500 lines of TypeScript across 3 applications and a shared engine |
| Status | Live in production; published on the Chrome Web Store |
| First deploy | September 2026, from brief to verified production |
| Since then | Admin portal, affiliate system, search-term intelligence, a second extension |
Advertisers pay for every click, but the landing page decides the return
Most wasted spend is not a bidding mistake. It is a page with no clear call to action, a nine-field form, a phone number that is not clickable on mobile, or conversion tracking that was never configured, so the campaign optimises against nothing.
The tools marketers already had answered different questions. Performance auditors measure load speed. SEO crawlers measure organic ranking potential. Neither answers the one question a media buyer asks before launching a campaign: if I send paid traffic to this page, what will stop it from converting?
That question also has to be answered in seconds, inside the browser, on any page, without asking the user to install a crawler or hand over site credentials. Agencies auditing a prospect's page have no access to that prospect's analytics or CMS at all.
1-click in-browser diagnosis with ranked commercial impact
The user opens any public landing page, clicks one button in the extension, and gets a score out of 100 within seconds. Six category scores sit under it: paid-search readiness, conversion, tracking health, SEO, a quick technical check, and trust. Every finding carries the evidence we saw on the page, why it matters for paid traffic, and a concrete fix, ranked by likely commercial impact.

Three things make the output usable rather than generic:
- Evidence, not adjectives: A finding quotes the actual headline, the form field count, or the missing tag, so the marketer can act without re-auditing the page by hand.
- Honest wording on tracking:Where a tag's behaviour cannot be proven from the page source, the report says “could not verify” instead of guessing. False confidence about conversion tracking is worse than no answer.
- Message match: The user enters their target keyword and ad copy, and the system scores how well the page delivers on the promise of the ad, then rewrites the headline to close the gap.

Free accounts get a limited number of audits with deterministic scoring. Paid tiers add AI-written recommendations, the AI copy rewriter, full tracking analysis, unlimited history and downloadable PDF reports. An agency tier adds white-label reports and client labels, and credit packs let heavy users top up beyond their plan.
The platform has since grown past the original brief: a second extension that audits live Google and Meta ad campaigns, a search-term intelligence engine that clusters and triages search queries from an uploaded report, an admin portal with email campaigns, an affiliate and referral system, and AppSumo licence redemption.
Decoupled client extraction, server-side entitlement & shared engine

The extension extracts the page in the user's own browser and posts structured data; the result returns to the popup and is stored against the user's account. A pnpm monorepo holds three applications and one shared package, so the scoring engine that runs on the server is the same code the extension falls back to when the network is unavailable.
52 deterministic checks: the AI layer can never alter the score
Scores are deterministic: the same page always produces the same number, and the AI layer can never move it.
That was a deliberate product decision. A score that drifts between runs is worthless to an agency putting it in front of a client.
Fifty-two checks run against the extracted page data. Forty-six cover the page itself, from headline clarity and form length to tap-target size and broken internal links; six cover tracking health. Each check returns a severity, the evidence behind it, a recommended fix, and a point score out of its own maximum.
Three-step arithmetic rules:
- Point awards: Each check awards points out of its maximum inside one category. A clear call to action is worth 15 points in paid-search readiness; a page with no CTA at all scores zero there and raises a critical issue.
- Category normalization: Each category normalises to 0–100 by dividing the points awarded by the points available in that category.
- Weighted aggregate: The six category scores combine into the overall score using fixed weights that sum to 100.

Weighting is where the product's opinion lives. Paid-search readiness carries the most weight because it is the question the user came to ask, and raw technical checks carry the least because a fast page that nobody can convert on is still a failure. The checks themselves are pure functions in a shared package, so the extension can run the identical engine offline when the backend is unreachable, and the user still gets a real audit instead of an error.

Strictly schema-constrained reasoning & sub-cent unit economics
AI adds interpretation, prioritisation and copywriting on top of the deterministic result. It explains which findings cost the most money, drafts replacement headlines and meta tags, and scores how well the page matches the ad. It never sets a score.

Everything the model returns is schema-constrained. The same Zod schemas that type the application are sent to the model as JSON Schema, and the reply is validated before it is stored. An invalid reply triggers one corrective retry that quotes the validation error; if the provider rejects the schema parameter itself, the call automatically falls back to describing the schema in the prompt. Unparseable output degrades to the deterministic audit rather than failing the request.
The provider sits behind a clean interface, which proved its worth mid-project:
The build originally shipped on Anthropic's Claude; the client later asked to move to Google Gemini for cost reasons. That switch touched one new adapter file and a configuration flag, not the routes, the schemas or the test suites.
Tuning the model was a measured exercise rather than a guess. A dedicated pass in September 2026 produced this:
| Measure | Before tuning | After tuning | Improvement |
|---|---|---|---|
| Audit with AI analysis | 43.8 s | 17.3 s | 60.5% faster |
| AI copy rewrite | 19.8 s | 11.6 s | 41.4% faster |
The gain came from capping the model's reasoning budget per task, giving deep analysis a real but bounded allowance and giving keyword matching none at all, since it adds nothing there. A quality rubric in the prompt forces every finding to cite something actually present on the page, which is what stops the output drifting into generic advice. Results are cached for 24 hours against a content hash, so re-auditing an unchanged page costs nothing, and a full audit with rewrite runs well under a cent.
Architectural defense: eliminating SSRF, RLS isolation & zero secrets
A browser extension that reads web pages and a backend that accepts URLs are both attractive targets, so the threat model shaped the architecture rather than being bolted on afterwards.
The backend never fetches user-supplied URLs
The extension extracts the page in the user's browser and posts structured data. This removes server-side request forgery (SSRF) as a vulnerability class instead of relying on regex filters. A secondary URL guard blocks private ranges, loopback, and cloud metadata.
The client decides nothing that matters
Identity comes from a verified token, plan entitlement comes from the billing webhook, and quotas are consumed by atomic database functions. A Postgres database trigger prevents users from modifying their own subscription tier even in a legitimate session.
Tenant isolation in Postgres (RLS)
Row Level Security policies restrict every table to the owning user. Ownership is double-checked in the service layer, returning 404 Not Found rather than 403 Forbidden to prevent enumeration of audit identifiers.
The extension collects structure, not secrets
Asks for 3 permissions and no host permissions. It runs only when clicked. It never reads form values, passwords, cookies, or storage. Tests explicitly assert no password field values enter payloads. Raw DOM data is pruned after 24 hours.
Supporting controls: Per-request nonce CSP · Per-IP rate limiting · Signature-verified, idempotent billing webhooks · Local token verification to eliminate auth hops · Minimal error responses exposing only request IDs.
Idempotent Stripe integration & revenue edge cases handled cleanly
The product sells a free tier, a monthly subscription, a discounted annual plan, an agency tier and credit top-ups, all through Stripe Checkout and the Stripe customer portal. The application never touches card details.
Subscription state is derived exclusively from Stripe webhooks. The interesting work was in the edge cases that quietly cost real money if they are missed:
- Deleting an account cancels the subscription first: Without this, a user who deletes their account keeps getting charged for a product they can no longer access, and finds out on their next statement.
- Upgrades modify the existing subscription: Moving between monthly and agency tiers updates the subscription in place with proration instead of opening a second checkout. Buying an annual plan cancels the monthly subscription on activation.
- Webhook handling is idempotent and retry-safe:Events are recorded by id so redeliveries cannot double-apply, and locks are released if processing fails so Stripe's retry succeeds.
- Stale events cannot downgrade a paying customer: A cancellation notice for a subscription that has already been superseded is recognized and safely ignored.
- Usage resets on the billing anniversary: Not the calendar month, so a subscriber who joins on the 20th is not reset ten days later.
The same billing infrastructure now powers AppSumo licence key redemptions and an affiliate referral programme with automated commission tracking.
176 automated tests, golden page fixtures & production verification scripts
The suite runs 176 automated tests across the shared engine, the backend and the extension. They are weighted towards the things that would cost money or trust if they broke, not towards vanity coverage percentages.
Scoring pinned to real production pages
Golden fixtures hold genuine extractions captured from live commercial sites with the shipping extractor. Tests assert exact point scores and issue identifiers, so engine revisions register as explicit, reviewable git diffs rather than silent drift.
Adversarial security test suites
Dozens of forged URLs covering loopback, private RFC-1918 subnets, and AWS/GCP metadata endpoints are asserted to be rejected. Cross-user reads and deletes must return 404, CORS headers reject unknown origins, and internal traces never touch responses.
Simulated Stripe lifecycle tests
Duplicate webhook deliveries, out-of-order cancellations, mid-cycle tier changes, and prorations are simulated against the billing engine to guarantee zero double-charges or lost access.
Extractor containment verification
A fixture DOM seeded with password and credit card inputs asserts that no sensitive values ever enter the extraction payload. A separate test minifies the extractor identically to production and executes it inside a clean JSDOM instance.
Production Verification Scripts:
Beyond unit tests, two automated scripts verify the live environment itself before every release. One connects directly to the Supabase Postgres instance to verify RLS isolation and triggers with throwaway accounts. The second drives the live API end-to-end as an authenticated user, testing quotas, premium locks, and cleanup scripts.
Engineering realities, failure modes & production edge cases
AI silently absent in production
After launch, audits completed correctly but arrived with no AI analysis. Because the system is deterministic-first, users still got a full audit rather than an error, which is exactly the designed behaviour but also hides the fault. One structured log line named the cause: the model provider returned a quota error because prepaid credits were exhausted. Graceful degradation protected the user; structured logging protected the diagnosis.
An audit that outran its own client
The first production measurement of an AI audit was 43.8 seconds against an extension timeout of 45 seconds. Users intermittently saw the offline fallback instead of the paid result they waited for. We capped the model's reasoning budget per task, raised the server function allowance, extended the client timeout with honest progress copy, and brought the exact same audit down to 17.3 seconds.
Rejected by the Chrome Web Store
The initial submission was refused for keyword spam. The cause was a single bullet in the listing that named nine tracking products in a row, which Google's policy filter flags as keyword stuffing. Zero code changed: we rewrote the store listing in natural conversational sentences, mentioning the platform once in context, and the extension was promptly approved.
A bug only real pages could reveal
Capturing golden fixtures from live commercial sites exposed a flaw synthetic fixtures never could. Text pulled from a detached copy of the DOM ran adjacent blocks together, turning “reviews” and a timestamp into one concatenated token and causing the engine to miss a review signal plainly visible on the screen. The extractor now walks live text nodes with proper whitespace separators.
A platform constraint that forced a better design
The hosting platform refused to store browser-exposed variables as secrets, colliding with Next.js public-variable conventions. Rather than hacking workarounds, we moved to plain server environment variables and deliver the two public values to the browser via a nonce-protected script tag rendered per request. Configuration is now cleanly unified on the server.
From written brief to published extension & paying subscribers
The product went from a written brief to a deployed, independently verified system in September 2026, and the extension is published on the Chrome Web Store. Billing runs in live mode, audits run against real pages, and the platform has kept shipping since.
| Outcome | Production Detail |
|---|---|
| Shipped | Chrome extension, web dashboard and API, live on a production domain |
| Audit engine | 52 deterministic checks across six weighted categories |
| AI latency | Cut from 43.8 s to 17.3 s by the September tuning pass |
| AI cost | < 1¢ per audit, with a 24-hour result cache |
| Automated tests | 176, concentrated on security, billing and scoring stability |
| Live verification | Database, API and billing checked against production by repeatable scripts |
| Database | Nine incremental migrations delivered as the product grew |
| Codebase | ~21,500 lines of TypeScript, three applications, one shared engine |
The engineering decisions have held up under growth. Because scoring lives in a shared package of pure functions, a second extension for auditing live ad campaigns reused the same infrastructure. Because the provider sits behind an interface, swapping the AI vendor cost a day rather than a rewrite. Because entitlement is enforced server-side, adding credit packs, affiliate commissions and marketplace licence redemption did not require revisiting the permission model.
This is an early-stage product, so the honest outcome measures are engineering ones: it is live, it is paid-capable, it is tested, and it has absorbed four significant feature additions since launch without architectural rework.
Modern TypeScript monorepo with production-grade boundaries
| Architecture Layer | Technology Choices |
|---|---|
| Language | TypeScript throughout, strict mode, pnpm monorepo |
| Extension | Manifest V3, Vite, React 19, Tailwind CSS |
| Web & API | Next.js 16 App Router, React Server Components, Route Handlers |
| Data | Supabase Postgres with Row Level Security, SQL migrations, scheduled cleanup jobs |
| Auth | Supabase Auth, email and Google sign-in, local JWT verification |
| Payments | Stripe Checkout, Customer Portal, signature-verified webhooks |
| AI Inference | Google Gemini with JSON-schema structured output; Anthropic Claude selectable |
| Validation | Zod schemas shared across extension, API and model contracts |
| Documents | Server-rendered PDF reports with white-label branding |
| Testing | Vitest, React Testing Library, JSDOM, golden fixtures, live environment scripts |
| Hosting | Vercel with per-request nonce CSP and scheduled cron jobs |
Principles proven across this build
- A deterministic core with AI on top, not AI as the product: Customers get a repeatable number they can defend to their own clients, the system still works when the model is unavailable, and the AI bill stays under a cent per use.
- Security designed into the architecture: Choosing never to fetch user URLs eliminated an entire vulnerability class instead of filtering it. Entitlement, quotas and ownership are decided by the server and the database, never by the client.
- Privacy as a product constraint: The extension reads page structure and nothing else, raw content expires on a schedule, and there are tests that fail if a form value ever reaches the payload.
- Testing aimed at consequences: Real captured pages pin the scoring, adversarial inputs pin the security boundary, simulated billing events pin the revenue path, and scripts verify the live environment before release.
- Boundaries where change is likely: A vendor swap, a new pricing model and three new product surfaces all landed without reworking the foundations.
Planning something similar?
If you are building a product where correctness, billing and user trust all have to hold at once, this is the standard of engineering we build to.