Source
## 3. Sub-Account Management ### Account Inventory - 10+ sub-accounts confirmed, including: House Cleaning, CTR Geeks, Green Grid Goblins, Better Map Rankings, Brand, Stealth Code LTD, Local Influence, Rem Growth, Luxury Listing Media, Karma Movers - Sub-account access restricted per user (e.g., Brian Kato given admin on specific accounts only) ### User Management Pattern - Created user Brian Kato (bkato@fusionvine.com) as Admin with voice AI and conversation AI agent permissions - Restricted to specific sub-accounts only (House Cleaning, CTR G., Green Grid Goblins, BMR, Brand) - Individual user accounts deleted for other staff; consolidated under shared "hello@ironautomations.com" account with logo-based persona - Rationale: GHL limits one native Google account per sub-account ### Snapshot Inventory (29 total, audited 2026-05-07) - Active keepers: BMR, CTR, CTR Geeks 2024, Patriot Pros - 14-18 "dead weight" snapshots identified for deletion: duplicates of Profit Launch Template, stale DAH marketplace imports from 2022 - All 29 snapshots unassigned to sub-accounts at audit time - Nuke list created for batch deletion via UI ### Snapshot-Based Product Architecture - GHL snapshots are the distribution mechanism for info-product offers - n8n workflows migrated BACK into native GHL workflows specifically to enable snapshot packaging - Goal: create a high-quality distributable snapshot as part of Iron Automations' product suite ### GHL Marketplace Strategy - Built functional snapshot via API in Green Grid Goblins account: 5 custom fields (Dashboard URL, Industry, etc.), 3 tags, "SEO Dashboard Demo Call" calendar - Marketplace listing drafted with pricing strategy - Custom menu link SOP created (`ghl-custom-menu-link-sop.md`) for embedding external dashboards into GHL sidebar - PowerShell script (`ghl-setup-script.psl`) built for reusable API calls to automate future sub-account setups - 8 screenshots required for marketplace submission ---
ExtractFactgino
May 9, 05:35 AM
## Key Personnel (GHL Context) - **Mike Merlino** -- product architecture, marketing infrastructure, all GHL strategic decisions - **Scott** -- client-facing sales, setting, onboarding; receives "clean inbox" notifications for engaged leads - **Martina** -- VA handling funnel setup, event promotion, GHL landing page configuration - **Brian Kato** -- Fusion Vine partnership; admin access to specific sub-accounts; GHL A2P and workflow discussions - **Damjan Nikolic** -- GHL implementation, A2P setup for client sub-accounts (Karma Movers/LocalWise Digital LLC) ---
ExtractFactvox
May 9, 05:35 AM
# Gino GHL Insights -- Chat Backup Mining Extract **Extracted:** 2026-05-09 **Sources:** universal-memory annotations, Skill-Building chats, Coding-Projects chats, OpenClaw-Telegram logs **Agent:** Gino (GHL Specialist, Iron Automations) ---
ExtractFactgino
May 9, 05:35 AM
## 4. Funnel & Pipeline ### Funnel Cloning for Events - Cloned "GGG Workshop Oct 29" to "GGG Workshop April 8th" for rapid event funnel deployment - Standard process: clone simplest existing funnel, modify wording, attach correct Zoom link, update thank-you page - Martina (VA) corrected: must use GHL landing pages for webinar registration to ensure lead capture, not direct Zoom links ### Funnel Types Deployed - Free Marketing Audit Funnel (Local Influence) - GGG Webinar / GGG Workshop series - SEO NEO funnel - VSSL (Video Sales Letter) funnel for home service businesses - DFY Service Form with multi-service picker ### VSSL Funnel Pattern - Removed initial quiz question; replaced with "claim your spot" CTA - Custom-coded forms pass lead data to GHL AND Meta Conversion API (CAPI) simultaneously - Eliminates redundant data entry while maintaining both GHL and Meta tracking ### Iron ACQ Architecture - Lead gen pipeline: Google Maps scraping -> enrichment -> verification -> push to Instantly/GHL - Local Ollama instance (3090 GPU) for data normalization; Gemini Pro as fallback - Meta CAPI + GHL funnel + AI setter + setter-to-closer handoff ### Custom Field Mapping (DFY Form) - Business Name, Niche, Description, Target Location, GBP Map URL, Social Media URLs, Targeted Keywords - Each mapped to specific GHL custom field IDs and keys - Critical for accurate data transfer between external forms and GHL CRM ---
ExtractPatterncarlosvox
May 9, 05:35 AM
## 1. Workflow Patterns ### DFY Service Form Pipeline (3-workflow architecture) - **01. DFY Payment Received** -- triggers on payment confirmation; uses conditional logic based on service count and payment status to route fulfillment - **02. DFY Form Submission** -- triggers on form submit; creates GHL contact + opportunity, adds notes, fires webhook, sends email notification. Stores data in Supabase in parallel - **03. Project Delivered** -- fires email + 7-day wait sequence post-delivery - Architecture confirmed across Stealth Code LTD sub-account (source: 2026-04-02, 2026-04-03 annotations) ### Workflow Cloning Strategy (critical pattern) - Never modify live GHL workflows directly. Always clone first - Example: cloned "02. DFY Form Submission" to "DFY Auto Service Form" with trigger changed to "Contact Tag Added - dfy-service-form" - Preserves existing automation while enabling dynamic payment link creation - Decision documented: "don't fuck up what's working" (source: 2026-04-03 annotation) ### Dynamic Payment Link Generation - GHL workflows cannot natively create payment links dynamically based on variable service counts - Workaround: use `{{opportunity.monetary_value}}` or `{{contact.custom_field.total_price}}` in invoice creation step of cloned workflow - Static payment links rejected; dynamic URLs mandatory - Invoice API at `https://services.leadconnectorhq.com/invoices/` returned 422/500 errors during programmatic attempts, forcing workflow-based approach ### Workflow Duplication Over Building From Scratch - GHL workflow builder UI has severe performance issues: blank pages, loading delays, screenshot capture timeouts - Browser automation (Playwright) against the workflow builder is "painfully slow and unreliable" - Operational decision: always duplicate and modify existing workflows rather than building new ones from scratch (source: 2026-04-04 annotation) ### Eugene's 3-Minute Delay - On AI setter instant form leads, insert a 3-minute wait node before first follow-up message - Purpose: reduces "bot smell" -- makes responses feel human-timed rather than instant-robotic ### Lead Classification Filter - Only push "Interested" and "Question" lead classifications from Instantly API to GHL - Filter out "Out of Office" and "Not Interested" replies before CRM entry - Keeps the GHL pipeline clean and prevents setter time waste on dead leads ### GHL Pipeline Stages (9-stage model) - Stages include: New Lead, Contacted, Qualified, Proposal Sent, Report Delivered, Campaign Complete, Reorder/Retainer, Closed Won, Closed Lost - Pipeline automation partially built; later stages (Report Delivered through Reorder) needed new email sequences - "SEO Dashboard Sales" pipeline manually created in UI due to API token scope limitations (no pipeline write access) ### Inbox Management Architecture - All outbound messages marked as read in GHL - Only engaged inbound conversations trigger notifications for human setter (Scott) - "Clean inbox" principle: the setter only sees real conversations, not their own outbound blasts ### Inbound SMS Reply Logging - Custom Python webhook logs all inbound SMS replies to GHL conversation threads - Permanent workaround for unreliable native Signal House/GHL threading integration - Ensures conversation continuity even when Signal House drops thread context ---
ExtractPatterncarlosvox
May 9, 05:35 AM
## 5. Cold SMS & Outreach ### Python Sequencer (not n8n) - Cold SMS engine actively migrated from n8n to standalone Python-based architecture - Rationale: scalability, reduced lag, more control over sequencing and slot windows - Python is the standard; n8n is deprecated for this use case ### Signal House - Used as the upstream SMS provider for cold outreach - Experienced global outage/billing issue with upstream partner causing all outbound SMS to fail with "Technical error" - Native Signal House/GHL threading integration is unreliable (hence the custom Python webhook workaround) ### Lead Deduplication - Cleaned ~2,400 invalid/overlapping leads from one campaign - Implemented deduplication check in push script before CRM entry - Purpose: prevents "muddiness" in the GHL CRM ### Lead Volume & Verification - Texas realtors scrape: ~6,263 leads (Bywaters Media) - Book & House: 6,036 new leads verified before push to Instantly - DataImpulse proxy credentials must be kept current or scrapers stall ### Niche Targeting - Blue collar trades prioritized: roofing, plumbing, HVAC, electrician, cleaning - High average order value + high demand for automation - Volatile niches (crypto, etc.) explicitly rejected ---
ExtractPatternginocarlos
May 9, 05:35 AM
## Reference: Communities - GHL Official Facebook Group ("GoHighLevel Official Community") - r/gohighlevel (reddit.com/r/gohighlevel) - GHL Snapshots via HighLevel Marketplace (pre-built funnels) ---
ExtractFactvox
May 9, 05:35 AM
## 6. GHL API Usage ### Private API (backend.leadconnectorhq.com) - Accessed via Playwright-based authentication capture - Extracts JWT from logged-in browser session: `GHL_FIREBASE_JWT`, `GHL_JWT`, `GHL_AUTH_TOKEN`, `GHL_AGENCY_API_KEY` - Enables programmatic CRUD on workflows NOT exposed via public API - Script: `capture_auth.py` bypasses page-sandbox restrictions blocking standard JWT extraction - Client: `ghl_client.py` manages both public PIT tokens and private backend headers - Methodology sourced from "Randy's" original approach documented in `GHL.md` transcript (ghl-sop.vercel.app/topics/private-api) ### Private API Capabilities Confirmed - Workflow CRUD (create, read, update, delete) - Trust Center submissions - Snapshot management - Endpoint discovery via 404 probing after auth works ### Public API Limitations Discovered - No pipeline write access via API token scope -- pipeline stages must be created manually in UI - Invoice API (`services.leadconnectorhq.com/invoices/`) returns 422/500 on programmatic creation attempts - Private integration keys configured with specific scopes (contacts, tags, notes) per sub-account ### Token Extraction Challenges - Multiple methods failed: Base64 return blocked, clipboard requiring user gesture, download blocked, localhost beacon mixed-content, CORS blocked for direct fetch - Chrome extension safety features block programmatic extraction - Solution: Playwright-controlled browser (Option A) selected for robustness and session-refresh capabilities - DevTools console snippet provided as manual fallback ### API-Driven Snapshot Creation - Custom fields, tags, and calendars created via API in Green Grid Goblins account - PowerShell script for reusable sub-account setup automation - Cross-account snapshot replication via private API snapshot endpoint ---
ExtractArchitecturecarlosvox
May 9, 05:35 AM
## 2. A2P & Compliance ### A2P Registration Status - BMR (Better Map Rankings) SMS infrastructure audited: 8 phone numbers tracked with individual A2P approval statuses - Chat widget shortcut is the standard method: auto-injects compliant Terms/Privacy, first-try Trust Center approval - A2P compliance is non-negotiable -- never skip registration steps ### Messaging Limits - Default: 200 messages/day per number - After A2P clears: submit for 1500/day bump - Must be done per number, per sub-account ### A2P for Client Sub-Accounts - Damjan tasked with GHL A2P setup for Karma Movers (LocalWise Digital LLC sub-account) - Each sub-account requires its own A2P registration and Trust Center submission - Sub-accounts with unregistered numbers will have messages silently dropped or throttled ---
ExtractFactgino
May 9, 05:35 AM
## Source Annotation IDs (for traceability) - `53bd20a0` -- DFY webhook debugging, workflow architecture (2026-04-02) - `6b27fd53` -- DFY workflow cloning, dynamic payment links (2026-04-03) - `dcf51c91` -- Funnel cloning, Martina correction (2026-04-03) - `9aeb7fc4` -- Workflow duplication strategy, pipeline stages (2026-04-04) - `513f75c8` -- Cold SMS Python migration, private API discovery, Signal House outage (2026-04-14) - `5d2563e4` -- n8n-to-GHL migration, email deliverability, Iron ACQ (2026-04-14) - `407cbaa4` -- Gino provisioning, Playwright auth, BMR SMS audit (2026-04-15) - `a0613d78` -- User management, sub-account permissions, Fusion Vine (2026-04-15) - `125e44a9` -- Token extraction challenges, GHL auth (2026-04-15) - `df84e953` -- Gino agent creation, mikemerlino.com strategy (2026-04-16) - `fd35d9fc` -- A2P for Karma Movers, Damjan arrangements (2026-04-19) - `d5b2f1f5` -- Snapshot API, marketplace listing, pipeline limitations (2026-05-06) - `6120d4d1` -- 29-snapshot audit, cleanup nuke list (2026-05-07)
ExtractFactgino
May 9, 05:35 AM
## Reference: GHL YouTube Channels (Vetted by Mike) - **HLGuy (Ray O'Daniel)** -- most technical GHL content, no fluff - **Alex Heiden** -- deep GHL workflows and automations - **ItsKeaton** -- GHL builds and tutorials - **Lead Gen Jay** -- GHL for lead generation - **Robb Bailey** -- GHL database reactivation and campaigns - **Nate Morse** -- GHL snapshots and builds - **Flightswag** -- VAPI and GoHighLevel voice agents - **GoHighLevel (official)** -- platform tutorials
ExtractPreferencevox
May 9, 05:35 AM
## 7. Anti-Patterns (What Failed) ### Building Workflows From Scratch via Browser Automation - GHL workflow builder UI freezes, goes blank, and times out under Playwright control - Screenshot capture during automation is unreliable - Resolution: always duplicate existing workflows and modify ### Modifying Live Workflows Directly - Risk of breaking working automation for all current leads - Resolution: clone-and-swap pattern with new trigger tags ### Static Payment Links - Do not scale with variable service counts - GHL cannot natively generate dynamic payment URLs in workflow - Resolution: invoice-based approach using custom field values ### n8n for Cold SMS - Lag, reduced control, harder to package into snapshots - Resolution: migrated to standalone Python sequencer ### Direct Zoom Links for Event Registration - Bypasses GHL lead capture entirely - VA (Martina) used direct Zoom links instead of GHL funnel pages - Resolution: always use GHL landing pages with embedded Zoom info ### Signal House Native Threading - Unreliable: drops thread context, breaks conversation continuity - Resolution: custom Python webhook to manually log replies to GHL threads ### GHL Email Deliverability (Native SMTP) - GHL-sent emails hitting spam folders - Resolution: transitioned to Google Workspace SMTP via app passwords + DMARC configuration in Cloudflare - Result: 99% inboxing rate ### Wait-Node Testing Errors - During testing, a lead was accidentally "blasted" with multiple automated follow-ups - Resolution: manual contact with the lead to apologize; tighter testing protocols needed ### One Google Account Per Sub-Account Limitation - GHL restricts native Google account integration to one per sub-account - Attempted individual user accounts for staff; caused management overhead - Resolution: consolidated under shared account with unified logo persona ---
ExtractDecisioncarlosvox
May 9, 05:35 AM
## 5. Local Schema ### Core Schema Stack per Page Type All local sites use JSON-LD injected in `<head>`. Target: 300+ lines of schema per page average. **Root Layout (every page inherits)** ```json { "@context": "https://schema.org", "@graph": [ { "@type": ["LocalBusiness", "MovingCompany"], "@id": "https://domain.com/#business", "name": "Business Name", "url": "https://domain.com", "telephone": "(555) 555-5555", "address": { "@type": "PostalAddress", "streetAddress": "123 Main St", "addressLocality": "City", "addressRegion": "FL", "postalCode": "34201", "addressCountry": "US" }, "geo": { "@type": "GeoCoordinates", "latitude": 27.336, "longitude": -82.530 }, "openingHoursSpecification": [...], "aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "789" }, "priceRange": "$$" }, { "@type": "WebSite", "@id": "https://domain.com/#website", "url": "https://domain.com", "name": "Business Name", "potentialAction": { "@type": "SearchAction", "target": "https://domain.com/?s={search_term_string}", "query-input": "required name=search_term_string" } } ] } ``` **Niche @type Variants** - Moving company: `["LocalBusiness", "MovingCompany"]` - Med spa / aesthetics: `["LocalBusiness", "MedicalBusiness"]` - Plumber/HVAC/trades: `["LocalBusiness", "Plumber"]` (use Schema.org subtype) - Roofing: `["LocalBusiness", "RoofingContractor"]` - Generic service: `["LocalBusiness", "HomeAndConstructionBusiness"]` **Service Page Schema** ```json { "@type": "Service", "name": "Service Name in City", "provider": {"@id": "https://domain.com/#business"}, "areaServed": { "@type": "City", "name": "City Name" }, "description": "...", "offers": { "@type": "Offer", "price": "55.00", "priceCurrency": "USD", "priceSpecification": { "@type": "UnitPriceSpecification", "price": "55.00", "unitText": "per hour" } } } ``` **Area Page Schema** ```json { "@type": "Service", "name": "Service in Neighborhood", "areaServed": [ {"@type": "City", "name": "City"}, {"@type": "Neighborhood", "name": "Neighborhood"} ] } ``` **Blog Post / Article Schema** ```json { "@type": "Article", "headline": "Post Title", "author": {"@type": "Person", "name": "Author Name"}, "publisher": {"@id": "https://domain.com/#business"}, "datePublished": "YYYY-MM-DD", "dateModified": "YYYY-MM-DD" } ``` **FAQ Schema (add to service pages + blog posts)** ```json { "@type": "FAQPage", "mainEntity": [ { "@type": "Question", "name": "Question text here?", "acceptedAnswer": { "@type": "Answer", "text": "Answer text here." } } ] } ``` **BreadcrumbList (every subpage)** ```json { "@type": "BreadcrumbList", "itemListElement": [ {"@type": "ListItem", "position": 1, "name": "Home", "item": "https://domain.com"}, {"@type": "ListItem", "position": 2, "name": "Services", "item": "https://domain.com/services"}, {"@type": "ListItem", "position": 3, "name": "Service Name", "item": "https://domain.com/services/service-slug"} ] } ``` ### Schema Insights from Terry Samuels (SEO Rockstars 2020) - Schema is a direct ranking signal, not just a rich snippet enabler. - Pages with comprehensive schema outrank identical content pages without schema when other factors are equal. - Schema stacking (multiple @type values in the @graph) tells Google more about the entity — more signal, not more noise. - Entity disambiguation: the `@id` property on LocalBusiness links all schema on the site to a single canonical entity definition. Always use it. ### LLM Visibility Schema (from MDW research, Apr 2026) To appear in AI answer summaries (ChatGPT, Perplexity, Gemini AI Overviews): - AggregateRating schema is mandatory — LLMs cite rating + review count - Author/Person schema on team pages builds entity authority for professional services - FAQPage schema feeds directly into PAA and AI summary panels - Minimum threshold for AI visibility: 150+ Google reviews + 20+ content pages + schema on every page ---
ExtractArchitectureghost
May 9, 05:28 AM
## 3. Geogrid & Maps ### Geogrid Fundamentals - Tool: LocalViking is the primary geogrid rank tracker in use. - Grid setup: center point on the business address. Grid size depends on service area — 7x7 for tight urban, 13x13 for suburban, 21x21 for wide rural service area. - Reporting cadence: baseline on day 1, then monthly delta report. Tie every rank movement to specific optimization action for attribution. - Proximity fact: you cannot change proximity. Google uses the searcher's location relative to the business. Accept this and focus on relevance + prominence signals to compensate. - Rank tie-breaking: when two businesses have equal proximity, relevance (categories, keywords, content) and prominence (reviews, links, citations) determine which wins the tie. ### Maps Pack Local Ranking Signals (Hierarchy) Based on pattern from conference SOPs and client data: 1. Google Business Profile completeness and category accuracy 2. Review velocity, sentiment, and keyword density in review text 3. On-page relevance of linked website (especially service pages) 4. Citation volume and NAP consistency 5. Backlinks to GMB-linked website 6. GMB post activity (recency signal) 7. Photo count and engagement 8. Proximity to searcher (cannot be changed) 9. Behavioral signals: clicks, direction requests, calls from GMB (CTR signals) ### CTR Manipulation Signals (Brent Bowser / CTR Geeks) - Brent Bowser built CTR Geeks as a tool for generating traffic signals to GMB listings and local pages. - Signal types: direct searches for the brand name + service, maps views, direction requests, calls from GMB, website clicks from GMB. - CTR Geeks course has 4 documented testimonials (Graham, Daryl Osborne, Bradley, James Slattery). - Pattern: simulated behavioral signals (views, clicks, calls) treated by Google's ranking algorithm as engagement indicators, which boost map pack position. - This is a gray-hat tactic — use for competitive markets where organic signals alone are insufficient. ### Maps Spam Fighting (Stephen Floyd SOP, 2020) Full SOP extracted from 2020 SEORockstars conference: 1. Identify spam: business name keyword stuffing (e.g., "Best Plumber Houston - 24hr Emergency"), fake address (residential or UPS Store), duplicate listings, fake reviews. 2. Reporting method: use "Suggest an edit" on the GMB listing to flag inaccurate business names. Report fake addresses directly via the "Report a problem" link on the map pin. 3. Mass reporting: if a competitor has 5+ spam indicators, report each issue separately — Google processes individual reports, not aggregate complaints. 4. Evidence package: screenshots of the listing with spam indicators highlighted, street view showing no business signage, reverse address lookup showing it's a residential or mail drop. 5. Success rate: Stephen Floyd reported 60-70% success rate on properly documented spam reports. 6. Timeline: Google typically reviews reports within 2-4 weeks. Follow up at day 30 if no action. 7. Maps spam tracker: maintain a spreadsheet of all spam reports submitted — date, listing name, CID, issue type, status. ### KML Files for Service Area - KML files define a custom service area polygon for GMB profiles that serve customers at their location (vs storefront). - Use Google My Maps to draw the service area polygon, export as KML, then upload to the GMB service area settings. - The KML polygon should match the service area pages built on the website — geographic consistency between GMB and on-page signals reinforces the relevance signal. - For moving companies: draw KML to cover origin + destination zones, not just a radius from the business address. ---
ExtractFactolivercarlos
May 9, 05:28 AM
## 4. Service Area SEO ### Hub + Spoke Page Architecture Standard local site structure used across Flat Fee Movers (Sarasota + Bradenton), Buy The Hour Movers (Brooklyn), MDW Aesthetics (Miami): ``` / (Home — brand + primary city) /services/ (service hub) /services/{service-slug}/ (individual service pages) /areas/ (area hub) /areas/{city-slug}/ (city area pages) /areas/{city-slug}/{service-slug}/ (city-service intersection pages) /blog/ (content hub) /blog/{post-slug}/ (individual blog posts) ``` ### Page Count Targets by Business Size - Minimum viable local site: 4 service pages + 5 geo posts + 16 PAA posts = 25 pages (from Mike's formula) - Standard local site: 25-50 pages at launch - Competitive local site (MDW build): 46 pages — 8 core, 10 service, 8 area, 15 blog, 4 utility - Enterprise multi-location: separate silo per location (6-7 pages each) + shared service pages at root level ### Neighborhood vs City Page Strategy - Think neighborhoods, not cities. "Botox in Brickell" beats "Botox in Miami" for conversion — Brickell searchers are signaling they want proximity. - Eight-neighborhood approach used for MDW Aesthetics: Brickell, Downtown Miami, Coral Gables, Miami Beach, South Beach, Wynwood, Coconut Grove, Doral. - Brooklyn build used 20+ neighborhood references woven into blog posts and GMB posts — not separate pages, but neighborhood density in content. - Area page content minimum: 1,000 words. Must include: neighborhood-specific intro paragraph, services offered in that area, customer testimonial from that area (or named neighborhood reference), embedded GMB map, local schema, FAQ section with neighborhood-specific PAA questions. ### Service Area Pages (SAPs) — Content Requirements - Never templated filler. Each SAP must have at least 3 unique sentences per 1,000 words that could only apply to that specific geography. - Local signals to embed: neighborhood landmarks, local event references, school district or zip code callouts, named streets or intersections where the service is frequently needed. - Image strategy for SAPs: one AI-generated neighborhood photo per page (Google Gemini CLI), geotagged before upload. - Internal links from SAPs: link to the parent service page, 2 adjacent area pages, 1 relevant blog post, and the contact/quote page. - SAPs should use breadcrumb navigation: Home > Areas > [City/Neighborhood] > [Service]. ### Site Architecture Pitfall (learned from multi-city silo builds) - Vercel static sites with catch-all rewrites (`vercel.json` wildcard route) cause soft 404s on dynamically generated city-service subpages. - Fix: explicit route entries in vercel.json for every city-service URL pattern, or generate all pages statically at build time and reference them in the sitemap. - Sitemap generator must scan the output directory for all HTML files — not just the page list the build script tracks internally. These two can diverge. - Single build script for all page types (main template pages + city-service subpages) prevents the design discontinuity problem where subpages don't match the style of main pages. ---
ExtractPatternghost
May 9, 05:28 AM
--- title: Ghost — Local SEO Insights Extract description: Encyclopedia-style reference mined from chat backup archives (Local-SEO-Sites, SEO-Rockstars, WordPress, Domain-Portfolio). Covers GMB optimization, citations, geogrid, service area SEO, schema, link building, and anti-patterns. agent: ghost date: 2026-05-09 sources: - Local-SEO-Sites/ (2025-12-31, 2026-01-04, 2026-01-27, 2026-02-16, 2026-02-18) - SEO-Rockstars/2025-12-16 (2012–2020 conference transcripts) - Domain-Portfolio/2026-03-01, 2026-03-08, 2026-03-09 --- # Ghost — Local SEO Insights Extract Mined from ~20 chat backup files across four archive folders. Intelligence comes from assistant synthesis outputs (user messages were stripped from backup format). All insights are observable patterns from actual client work and conference SOPs. ---
ExtractArchitectureghost
May 9, 05:28 AM
## 2. Citation & NAP ### Primary Citation Platforms (13 Tier 1) Priority order for new client builds (from Flat Fee Movers deployment checklist): 1. Google Business Profile (GMB) — if not done, start here 2. Yelp — claim/create, add full description, photos, categories, hours 3. BBB (Better Business Bureau) — paid accreditation if budget allows; drives trust signals 4. Facebook Business Page — complete all fields, add services section 5. LinkedIn Company Page — especially for B2B or professional services 6. Thumbtack — service area + categories + intro message 7. YellowPages — two separate entries possible (YP.com + superpages.com parent) 8. Superpages — separate submission from YellowPages despite shared ownership 9. Angi (formerly Angie's List) — moving, home services, trades especially 10. HomeAdvisor — service area, categories, request quotes enabled 11. Nextdoor Business — neighborhood-level visibility, very high trust in home services 12. Houzz — relevant for home services, remodeling, interior 13. MapQuest — still indexed by Bing/Apple Maps data pipelines ### Data Aggregators (4 mandatory) These seed dozens of downstream directories automatically. Submit here first, then Tier 1 manually. 1. Data Axle (formerly Infogroup) — dataaxle.com/business-listing 2. Neustar Localeze — neustar.biz/localeze 3. Foursquare — foursquare.com/business 4. Yelp — also functions as aggregator for Apple Maps data ### NAP Consistency Rules (5 rules) 1. Exact match to GMB — copy-paste the exact business name, address, and phone from the GMB profile. No abbreviations, no variations. 2. No cross-location mixing — each location gets its own NAP block. Never use Location A's phone number on Location B's citation. 3. USPS format for address — use standard USPS postal abbreviations (St not Street, Ave not Avenue). Verify with USPS address lookup tool. 4. Local phone number only — no toll-free numbers as the primary NAP phone. Call tracking numbers are acceptable if they are local-format and consistently applied. 5. Quarterly NAP audits — run a citation audit every 90 days minimum. Use BrightLocal or Whitespark. Fix any drift immediately. ### Canonical NAP Block Format ``` Business Name: [Exact legal name or DBA matching GMB] Address: [Street Number] [Street Name Abbrev], [City], [State] [ZIP] Phone: ([area code]) [3-digit]-[4-digit] Website: https://[domain.com]/?utm_source=citation&utm_medium=[directory] ``` ### Duplicate Detection - Same business name with different CID URLs (goo.gl vs google.com/maps?cid=) signals a duplicate or split listing. Merge or suppress the legacy listing. - Common duplication source: old GMBs created pre-2018 with short URLs. Audit these in the GMB database by checking for name collisions with different CID values. - Google's duplicate detection is imperfect. If two listings exist for the same address, the one with more engagement signals (reviews, posts, photos) typically wins — but both should be manually merged. ---
ExtractFactolivercarlos
May 9, 05:28 AM
## 1. GMB Optimization ### Profile Completeness - Business description: max 750 characters. Formula — lead with primary keyword + city in sentence 1, then 2-3 service differentiators, close with call-to-action sentence. Never keyword-stuff sentence 1. - Q&A seeding: pre-populate 5-10 high-volume PAA questions as Q&As on the GMB profile. Own the Q&A section before competitors or spammers do. Include target keyword naturally in each answer. - Photos: minimum 10 at launch. Always include interior, exterior, team, and work-in-progress shots. Zero stock. Geotagged JPEGs only (embed GPS coordinates in EXIF before upload). - Attributes: fill every applicable attribute — wheelchair accessible, women-owned, veteran-owned, online estimates, etc. Attributes drive filter visibility in local pack. - Categories: primary category is the single most important ranking lever. Secondary categories add topical relevance but do not dilute the primary. Research competitors' primary categories before selecting. ### GMB Post Strategy - Post type: EVENT or OFFER type consistently outperforms WHAT'S NEW for engagement signals. - Duration: set end date 1 year out for evergreen offers. Never let posts expire without replacement. - Title: keyword-first, not brand-first. "Brooklyn Flat-Rate Movers — Spring Booking Now Open" not "Buy The Hour Movers Announces..." - Body: 150-300 words. Weave in 2-3 secondary keywords naturally. Include a neighborhood reference. - CTA buttons: "Book now" for service/transaction posts, "Call now" for consultation/emergency posts, "Learn more" for informational/blog posts. - Multi-location brands: write separate post versions per location. Never post identical text across both GMB profiles. Location-specific phone numbers, neighborhood references, and seasonal context must differ. - UTM tagging: append UTM parameters to all GMB post links. Pattern: `utm_source=gmb&utm_medium=post&utm_campaign={post-topic}&utm_content={location-slug}`. Enables GA4 attribution by location. - Velocity: at least 1 post per week. Dormant profiles lose ground in map pack. Consistent posting = activity signal. ### Review Strategy (from Mike's $100K testing data) - Reviews with keywords + photos outperform links as local pack signals. - Review sentiment is the strongest local ranking signal — outweighs entity authority. - Velocity matters more than total count. 5 reviews/month beats 50 reviews once with nothing since. - Review response: respond to every review within 48 hours. Include the business name + city + service in the response naturally ("Thanks for trusting Flat Fee Movers Sarasota with your move..."). - Prompting: give customers a direct link to the GMB review form. Never use a redirect or landing page in between — friction kills conversion. - Keyword-rich review prompting: ask customers to mention the specific service and city in their review. Example prompt: "If you'd like to help others find us, mentioning the specific service you used (e.g., 'local moving in Sarasota') would be especially helpful." ### UTM + CID Tracking - Every GMB profile should have a UTM-tagged website URL. Pattern: `?utm_source=gmb&utm_medium=organic&utm_campaign=local-pack&utm_content={location-slug}` - CID URL format: use `https://www.google.com/maps?cid={CID_NUMBER}` — this is the canonical format. Avoid goo.gl short URLs (legacy, unreliable for tracking). - CID extraction: CIDs are retrievable from the GMB URL when you click "Share" on a listing, or via Google Places API. - Multi-location database (from Mike's 540-record GMB DB): track CID URL, website URL, phone, GMB status (active/inactive/suspended), last verified date, and call tracking number per profile. ### Multilogin Browser Profiles - Assign a dedicated Multilogin browser profile per brand. Store the profile ID in the brand's database record. - One-click launch from domain portfolio dashboard — prevents accidental cross-account contamination. - Never manage multiple client GMBs from the same browser session or IP. ### Suspension Recovery - GBP Recovery Coach approach: 160+ item interactive checklist, 7 chapters (pre-suspension audit, during-suspension triage, evidence gathering, appeal writing, reinstatement, post-reinstatement hardening, monitoring). - Evidence kit: business license, utility bill showing business address, lease agreement or deed, photos of physical signage, supplier invoices with business name + address. Date-match all documents. - Appeal letter formula: state the business name and category, provide timeline of operation, attach evidence, cite the specific policy you believe you complied with, and offer to provide additional documentation. Never admit guilt or speculation. - Reinstatement rate improves significantly when the appeal is submitted within the first 30 days of suspension. - Post-reinstatement: immediately update all citation NAP to match reinstated GMB exactly. One mismatch can trigger re-review. - RAG AI coach (from PRD): OpenAI-powered coach that answers questions contextually from the 7-chapter handbook and checklist state. ---
ExtractFactolivercarlos
May 9, 05:28 AM
## 7. Anti-Patterns ### GMB / Profile Anti-Patterns - **Keyword stuffing the business name** — highest suspension risk factor. "Best Plumber Houston TX 24/7 Emergency" is a policy violation and a spam signal. Business name must match the legal or commonly known name exactly. - **Inconsistent hours** — GMB hours that don't match website hours confuse both users and Google's entity consolidation. Update both simultaneously. - **Identical descriptions across locations** — Google detects duplicate content in GMB descriptions. Each location profile needs a unique description. Even minor paraphrasing is insufficient — write fresh for each location. - **Same photos on all locations** — photos are an entity signal. Using identical photo sets across 10 location profiles dilutes their uniqueness signal. Each location should have location-specific photos. - **Leaving Q&A unmonitored** — competitors and spammers can post misleading Q&As on your GMB. Seed it with your own content and monitor weekly. - **Letting posts go dormant** — a GMB with no post activity for 90+ days signals an inactive business. Even a single weekly post prevents this. ### Citation / NAP Anti-Patterns - **Abbreviation inconsistency** — "St" vs "Street" vs "St." creates three different NAP strings. Google's entity matching is string-sensitive. Pick one format and apply it everywhere. - **Toll-free number in citations** — 1-800 numbers are not local signals. Use a local-format number as the primary NAP phone even if the business also has a toll-free line. - **Directory listing without photo** — citation entries with no photo get lower confidence scores from data aggregators. Always upload the logo or a business photo. - **Letting aggregator submissions sit without verification** — Data Axle and Neustar Localeze allow competitors to "suggest edits." Check your aggregator listings every quarter. ### On-Page / Content Anti-Patterns - **Stock photos** — never. Unsplash, Pexels, Pixabay, or any free stock service is prohibited. Only: Google Gemini AI-generated, client-provided, or CSS gradient placeholders. - **Generic "click here" or "learn more" anchor text on service links** — wastes internal link equity. Use descriptive keyword-rich anchors: "flat rate movers in Sarasota" not "click here." - **Same testimonials across all location pages** — if a client left a review about their Sarasota move, use it only on the Sarasota pages. Using it everywhere dilutes uniqueness. - **City name only in H1** — "Botox in Miami" as a lone H1 is thin. H1 should include the primary differentiator: "Botox Injections in Brickell Miami — Luxury Pricing, Expert Injectors." - **Arbitrary word count floors** — blog post length must match the #1 ranking competitor +10-20%. Never set a blanket 1,500-word floor if the top-ranked post is 800 words. - **No breadcrumbs on subpages** — breadcrumbs are both a UX signal and a BreadcrumbList schema opportunity. Every subpage (services, areas, blog posts) gets breadcrumbs. - **Missing canonical tags** — city-service intersection pages can create thin content at scale. Canonical tags prevent duplication penalties when content is similar across multiple city variants. ### Schema Anti-Patterns - **Generic Organization type** — using `@type: Organization` when the business is a local service provider wastes specificity. Always use `LocalBusiness` as the base, then add the niche subtype. - **Mismatched schema and page content** — if the schema says `aggregateRating: 4.9 / 789 reviews` but the page shows different numbers, it is a consistency violation. Keep schema data in sync with visible page content. - **No @id on LocalBusiness** — without `@id`, each page's schema is a disconnected entity. The `@id` URI ties all schema across the site to one canonical business entity. - **FAQPage schema on pages with no visible FAQ section** — Google requires FAQ schema to match the visible on-page content. Hidden or missing FAQ sections with schema present = quality violation. ### Site Architecture Anti-Patterns - **Catch-all Vercel rewrite on static sites** — wildcard `rewrite` in vercel.json causes soft 404s on dynamically-named city-service pages. Use explicit routes or static generation. - **Sitemap not covering all pages** — if the sitemap generator only tracks pages it personally created and misses pages generated by other build scripts, Google won't crawl the full site. Scan the output directory, not the internal page registry. - **Two separate build scripts with different styling** — if main template pages and city-service subpages are generated by different scripts, they often have design discontinuities. Single build script eliminates this. ### Multi-Location Anti-Patterns - **Cross-location phone number contamination** — Location A's phone number appearing on Location B's citation or page. This confuses call attribution and dilutes NAP trust for both locations. - **Identical UTM parameters across locations** — if both Sarasota and Bradenton GMBs use the same UTM tags, GA4 cannot distinguish traffic sources. Unique `utm_content` per location is mandatory. - **Reusing the same tracking number across inactive/active GMBs** — Mike manages 220+ GMBs with 278 SignalWire numbers and 52 CallFire numbers. Tracking numbers must be 1:1 with GMB profiles. Recycling a number from a suspended GMB to an active one can carry negative history. ---
ExtractPatternolivercarlos
May 9, 05:28 AM
## 6. Local Link Building ### Trust Fortress Architecture (Greg Montoya, SEO Rockstars 2015) The trust fortress approach treats link equity like a security perimeter: - **95%** of PBN links point to Tier 1 citations (Yelp, YP, BBB, directories) - **4%** of links point to Tier 2 web 2.0 properties (WordPress.com, Blogger, Tumblr) - **1%** of total links point directly to the money site Rationale: pointing PBN links directly at the money site leaves a visible footprint. Layering through citations and web 2.0s dilutes the footprint while still passing equity. ### Weebly 301 PBN Strategy (Carolyn Holzman, SEO Rockstars 2016) - Build Weebly microsites as buffer layer between PBN and money site - 301 redirect Weebly sites to the money site or Tier 1 citations - Carolyn's case study: 22,000+ backlinks acquired via this method - Risk profile: Weebly free sites are fragile — Weebly can deactivate them. Use paid Weebly accounts or mirror on GitHub Pages as backup. - 2024+ note: this is a gray-to-black hat tactic. Apply carefully in competitive niches where organic link acquisition is slow. ### Social Signals and Co-Citation (Josh, SEO Rockstars 2016) - Co-citation: getting your business name and URL mentioned together (without a link) on authoritative pages still passes relevance signal. - Social signals: Facebook shares, Google+ citations (historically), Twitter embeds — drive crawl budget and act as co-citation. - For local SEO, co-citation in local news articles and neighborhood blogs carries more weight than social share volume. - Strategy: get mentioned (even without a link) on local chamber of commerce sites, local news outlets, neighborhood association pages. ### NoFollow Links as Trust Signals (Dori Friend, SEO Rockstars 2015) - As of 2015 (the year of this data), NoFollow links from high-authority domains were more valuable as trust signals than DoFollow links from low-authority domains. - The trust transfer via NoFollow is not PageRank — it is entity co-occurrence and topical relevance. - Practical application: a NoFollow mention from a city government site, hospital, or university carries more trust signal than a DoFollow link from a low-DA directory. ### Link Silo Architecture (Moon Hussain, SEO Rockstars 2020) - Site structure and link silos were tested across 50 sites: 75% of sites ranked for 200+ keywords within 4 months with zero backlinks. - The silo structure creates internal link equity concentration: hub page accumulates PageRank from all subpages, then redistributes it via contextual links. - For local sites: service hub links to all service pages; service pages link back to hub and cross-link to adjacent services. - Never link from a service page to a competing service page's primary keyword anchor — use branded or generic anchors for cross-links. ### Negative SEO Defense (Ted Kubaitis, SEO Rockstars 2014 / Josh, 2016) - Monitor backlink profile monthly (Ahrefs/Majestic). Sudden spike in spammy backlinks is a negative SEO attack. - Disavow file: submit a disavow file to Google Search Console within 30 days of attack detection. Do not wait. - Velocity attacks: artificial link spikes timed with Googlebot crawl cycles (Ted Kubaitis 2014) — the penalty hits during the next quality signal refresh. - Fictitious URL attacks: spammers create 404 URLs on your domain and point spam links at those URLs. Monitor Search Console for crawl errors spiking on URLs you didn't create. ---
ExtractArchitectureolivercarlos
May 9, 05:28 AM
## Scale Reference — Mike's GMB Database Context for the scale of local SEO work across the portfolio: - 540 total GMB records (deduped to 493 unique) - 286 active / 127 inactive / remainder suspended or pending - Top niches: Roofing 141, Moving 97, HVAC 29, Dumpster 26, Electrician 17, Water Damage 17 - CID URL completeness: 80% — 20% of profiles missing CID (needs audit) - Website completeness: 78% - Phone completeness: 47% — over half of profiles have no tracked phone number (major gap) - Call tracking infrastructure: 278 SignalWire numbers, 52 CallFire numbers, 31 Twilio numbers on GMBs - Multilogin browser profiles: one per brand, stored in domain portfolio dashboard --- *Ghost — Local SEO Insights Extract — 2026-05-09* *Sources: 20 chat backup files across Local-SEO-Sites, SEO-Rockstars, Domain-Portfolio archive folders*
ExtractFactghost
May 9, 05:28 AM
## WP Security ### Hardening Checklist (Per Site) - File permissions: 755 directories, 644 files - wp-config.php: security keys configured, database prefix changed from `wp_` - Wordfence installed and firewall enabled - MainWP Child plugin kept updated (security surface) - SSL valid — MainWP SSL Monitor flags expiry <7 days as critical - SSH hardening on shared hosting where possible ### Alert Response Times | Issue | Response | |-------|----------| | Site down | 15 minutes | | SSL expiring <7 days | Same day | | Critical vulnerability (CVE) | Same day | | Plugin update available | Within 1 week | | Domain expiring <30 days | Within 1 week | ### Hacked Site Recovery Full 9-step SOP at: `C:\Users\mikem\.claude\skills\wordpress-expert\references\wordpress-hacked-site-recovery-sop.md` Steps include: core replacement, malware scan, credential rotation, WP Cerber deep scan, Sucuri WAF. ### Backup Strategy - UpdraftPlus managed via MainWP for bulk configuration - Always backup before applying updates to critical/high-value sites - Restore + ignore list is the rollback sequence (never just re-update) ---
ExtractDecisionwillie
May 9, 05:27 AM
# Willie — WordPress Insights Extract **Mined from:** Project Chats — WordPress/, Web-Dev/, Templates-Master/, Domain-Portfolio/, Home-General/, Users-mikem-claude-agents-workspaces-willie/, Skill-Evaluator/ **Date extracted:** 2026-05-09 **Agent:** Willie (WordPress Lead) ---
ExtractArchitecturewillie
May 9, 05:27 AM
## Elementor & Page Building ### Template Kits (57 Premium Kits) **Location:** `E:\LOC\Design Templates\elementor-pro\` (57 zips — do NOT unzip to D: first, import directly from zip into WordPress) **Import process:** WordPress > Elementor > Templates > Import Templates > select JSON files from unzipped kit **Niche matching quick-ref:** | Niche | Templates | |-------|-----------| | HVAC / AC | breezerve, colek, cooler, coolwash, heyheat, jezzcool, sejuk, plumberia | | Plumbing | handyc, plumbend, plumberkit, plumbero, plumber-paragon, plumble, renovirta, zedag | | Cleaning | cleanie, cleanor, cleansee, cleanuva, clino, dribo, hygienex, kleaning, klein, klinta, letsclean, resik, washup | | Roofing | chauni, estateroof, roofcrafters, roofixer, roofta, roofting, roovon, saqaf | | Construction | billdins, constkit, corner, horev, tozee | | Electrical | detroit, rewired | | Medical | healio, mediheal, neurova | | Digital agency | kavira | | Woodworking | woodpanel | **Decision rule:** These kits are for WordPress/Elementor only. Next.js/React sites use Cruip, Tailwind Plus, or Aceternity templates — NOT these Elementor kits. ### Elementor Theme Builder Structure ``` Theme Builder ├── Header (site-wide, sticky with shrink effect) ├── Footer (site-wide, with gradient CTA banner) ├── Single Post Template ├── Single Page Template ├── Archive Template └── WooCommerce Templates ``` ### Elementor Performance Settings (Always Configure) - CSS Print Method: External File - Improved Asset Loading: Enable - Font Display: Swap - Google Fonts: Disable (use local fonts instead) - Font Awesome: Load only used icons ### Custom CSS Pattern (Widget-level) Use `selector` keyword for widget-scoped CSS. Global CSS goes to Elementor > Custom CSS. ### Roofing Site Lessons - Old roofing site templates had duplicate headers — always check for this on imported template kits - GMB data (phone number, address, CID links) must be injected into H1 tags and schema on every page - Roofing sites need phone number + GMB info updated — Mike's directive from 2026-03-11 ### AI Summary Footer (Elementor Implementation) Skill: `ai-summary-footer` at `C:\Users\mikem\.claude\skills\ai-summary-footer\SKILL.md` For WordPress/Elementor: self-contained HTML + `<style>` + vanilla JS block, paste into any HTML widget. Variables to configure: brand_name, page_topic, site_url, page_url. Links out to ChatGPT, Claude, Perplexity, Grok with pre-filled authority-positioning prompts. No external CDN required — inline SVGs only. ---
ExtractArchitecturewillie
May 9, 05:27 AM
## Theme & Design ### Theme Selection by Context | Situation | Theme | |-----------|-------| | Client site, Elementor builds | Elementor's Hello theme (lightest Elementor-compatible) | | Performance-focused, no page builder | GeneratePress or Kadence | | Legacy client with Divi | Divi (active for Karma Movers until Next.js migration completes) | ### Karma Movers Migration (Active) - Active WP/Divi → Next.js rebuild - Site has 4.9 stars, high authority — preserve all existing URLs with redirect map - Redirect map is NON-NEGOTIABLE — mandatory on every migration - Check for orphan pages, broken internal links, 301 chains before cutover ### CSS Design System (When Building Custom) Pattern from roofing/cleaning site builds (reference for future WP theme customization): - CSS custom properties for shadows (4 tiers), radius, transitions - `.hero-section` with gradient overlay via `::after` pseudo-element - `.card` with hover `translateY(-4px)` + shadow + gold/brand border - `.glass` / `.glass-light` with `backdrop-filter: blur(16px)` - Font pairing: Playfair Display (serif, headings) + Inter (body) - Keyframe animations: `fadeInUp`, `pulse`, `shimmer` ---
ExtractDecisionwillie
May 9, 05:27 AM
## Standing Orders (Loaded Every Session) - Minimal plugins, maximum performance - Never skip redirect map on any migration - Schema on every page — Rank Math schema module + custom JSON-LD injection - Always "GMB" never "GBP" - WordPress builds go to Willie, NOT Merlin - Check MainWP dashboard for site health before manual investigation - Verify domain ownership in Namecheap before DNS changes - Roofing sites: phone number + GMB data + schema = three mandatory checks per page
ExtractPatternwillie
May 9, 05:27 AM
## WordPress Setup Patterns (Install, Config, Hosting) ### Hosting Infrastructure (Confirmed Active) | Host | Sites | Notes | |------|-------|-------| | WPX Hosting | 34+ sites, Elite Agency plan | MainWP dashboard at mainwp.abreumovers.com | | SiteGround | excelelectricians.com, moldremediationexperts.net | Both active since 2026-02-12, SSH configured | | Hostinger | 154 sites across 2 plans | Cloud Startup (u460774856) + Business Web Hosting (u504429740). API key available. | | A2 Hosting | ctrgeeks.com | Login: michael@ezmoneywealthsystems.com | **Credentials location:** `D:\Ecosystem\secrets\MASTER_API_KEYS.env` — all hosting credentials stored there. Never hardcode. **WPX site list (confirmed):** - Moving niche: 5starmovers.net, 5starmoversllc.com, abreumovers.com, flatfeemovers.com, flatfeemovers.net, miamimovers.co, karmamovers.com, mintmovers.com, movingcompaniesqueens.com, movingcompanysarasotafl.com, brooklynmovingcompanyllc.com - Agency hub: merlinomarketing.com **SiteGround SSH config:** - Host: ssh.mmerlino.com, Port: 18765, User: u2517-93jx74u91ttf - Key: ~/.ssh/siteground-cleanup-nopass - IP: 34.174.63.157 **Hostinger API:** - Base URL: developers.hostinger.com - API key in MASTER_API_KEYS.env - VPS API token also stored (may be older) ### First-Check Protocol - Before touching any site individually, check MainWP dashboard at mainwp.abreumovers.com first - MainWP shows site health, plugin update counts, PHP version, uptime across all WPX sites - Only SSH or WP-admin direct when MainWP shows something needs hands-on attention ### Domain Ownership - Primary registrar: Namecheap (account: merlinomarketing, API key in MASTER env) - Some domains also on Hostinger - SiteGround holds mmerlino.com domain - ALWAYS verify domain ownership in Namecheap before making DNS changes ---
ExtractFactwillie
May 9, 05:27 AM
## Plugin Decisions ### Standard Stack (Preferred) | Category | Plugin | Why | |----------|--------|-----| | SEO | Rank Math | Preferred over Yoast; schema module + custom JSON-LD injection built-in | | SEO (alt) | Yoast | Fallback when client already has it installed | | Performance | WP Rocket | Bulk cache clearing, CDN config, DB optimization via MainWP | | Image compression | ShortPixel | WebP conversion, integrates with WP Rocket | | CDN | Cloudflare | Also WAF/security layer | | Security | Wordfence | Integrates with MainWP for fleet management | | Builder | Elementor Pro | Most clients; has 57 template kits ready | | Builder (alt) | Kadence | Lighter weight alternative when Elementor is overkill | ### Minimal Plugin Rule If a plugin does one thing, use it for one thing only. No plugin stacks that duplicate functionality. Keep plugin count down — each plugin is a potential conflict, performance hit, and update liability. ### Known Plugin Conflicts / Gotchas - Cloudflare WAF can block MainWP Dashboard → Child communication — whitelist Dashboard IP in WAF rules - Wordfence, Sucuri, iThemes, Shield can all block MainWP — whitelist Dashboard IP in each - PHP max_execution_time too low = MainWP timeout errors — increase to 300 ---
ExtractDecisionwillie
May 9, 05:27 AM
## Anti-Patterns (WP Approaches That Failed or Were Rejected) ### Never Do - **Skip redirect map on migration** — non-negotiable standing order. Every URL must be mapped. - **Push WordPress builds to Merlin** — clear boundary: WP = Willie, not Merlin - **Make DNS changes without verifying domain ownership in Namecheap first** - **Use Cloudflare without whitelisting MainWP Dashboard IP** — causes 403 blocks on Child sync - **Leave WP Rocket cache stale after plugin updates** — always clear + preload after significant changes ### Design Anti-Patterns Found in Production - **Duplicate headers on imported template kits** — roofing sites had this from old templates; always check Theme Builder after importing a kit - **Generic flat Tailwind/utility-class page building without design system** — Flat Fee Cleaners site initial build looked "pretty shitty" compared to reference site because 3 parallel agents used flat utility classes without gradients, hover animations, blur effects, font pairing, or shadow depth. Fix: always define a CSS design system first before parallelizing page builds. ### WordPress → Next.js Conversion Market Context (Research, 2026-02-10/11) Mike explored the WP-to-Next.js converter market. Key finding: no single platform handles SEO automation + CMS field mapping + e-commerce conversion well. Platforms researched: WPConvert.ai (~$99+/mo), LovableConverter.com (free/freemium), ClonewebX ($10-300, 40K+ users, Elementor-focused). Not pursued further as of record date. ---
ExtractPatternwillie
May 9, 05:27 AM
## MainWP Management ### Dashboard - URL: https://mainwp.abreumovers.com/wp-admin/ - User: wpx1 - Manages all WPX-hosted WordPress sites ### Two APIs Available | API | Auth | Best for | |-----|------|----------| | REST API v2 | Bearer token | Traditional CRUD, monitoring, extensions | | Abilities API | Application Password (Basic auth) | AI agents, automation, batch ops (preferred) | **REST base:** `/wp-json/mainwp/v2/` **Abilities base:** `/wp-json/wp-abilities/v1/` ### Batch Operations - Abilities API auto-queues when >200 sites affected - Poll with `get-batch-job-status-v1` - Job timeout: 4h, persist 24h, processes 20 sites/chunk with 30s delay ### Connection Troubleshooting (In Order) 1. Verify MainWP Child plugin installed and activated on child site 2. Check Security ID matches on both sides 3. Confirm OpenSSL + cURL enabled on both servers 4. Check firewall/WAF not blocking Dashboard → Child requests 5. Whitelist Dashboard IP in Wordfence/Cloudflare if needed (Cloudflare: WAF > IP Access Rules > Allow) 6. Reconnect flow: Sync > Reconnect > Remove+Re-add > Full checklist ### Update Pipeline (Staged Rollout) | Stage | Action | Wait | |-------|--------|------| | Monday 2 AM | Sync all, detect updates | — | | Monday 3 AM | Apply canary (1-3 low-risk sites) | 24h | | Tuesday 3 AM | Apply non-critical (if canary passed) | 4-8h | | Wednesday 3 AM | Apply critical sites (backup first) | 24h | | Thursday | Review all, generate report | — | **Rollback:** Restore from backup → add to ignore list via `set-ignored-updates-v1` → report to developer. ### Extensions in Use - Security: Wordfence, Vulnerability Checker - Backup: UpdraftPlus - SEO: Rank Math - Performance: WP Rocket - Monitoring: Uptime, SSL Monitor, Domain Monitor - Reporting: Pro Reports (white-label PDFs) ---
ExtractArchitecturewillie
May 9, 05:27 AM
## 4. Transcription & Analysis Pipeline ### Lead Pipeline Architecture File: `src/services/leadPipeline.ts` ``` processCall(call) -> 1. Skip if no recording_url or already transcribed 2. Transcribe via AssemblyAI (transcribeAudio) 3. If transcription < 10 chars -> save empty, skip analysis 4. Analyze via Claude Sonnet 4.6 / GPT-4.1 hybrid (getBestAIProvider) 5. Format notes as human-readable backup 6. Save to Supabase call_log (structured columns + notes backup) 7. Apply revenue rules (may override AI estimate) 8. Save to IndexedDB as lead (if is_lead = true) ``` ### Structured Fields Extracted by AI Per-call analysis populates these DB columns: - `transcription` -- full text - `sentiment` -- positive/negative/neutral - `is_lead` -- boolean - `caller_name` -- extracted from conversation - `caller_email` -- if mentioned - `caller_address` -- if mentioned - `service_needed` -- normalized via serviceNormalizer - `reason_for_call` -- free text - `urgency_level` -- low/medium/high/emergency - `customer_type` -- residential/commercial - `key_points` -- array of bullet points - `next_steps` -- array of action items - `call_outcome` -- what happened - `follow_up_required` -- boolean - `ai_provider` -- which model analyzed it - `ai_confidence` -- confidence score - `appointment_booked` -- boolean - `company_hired` -- boolean - `revenue_estimated` -- dollar amount ### AssemblyAI Configuration - Upgraded from `nano` (deprecated) to `Universal-2` (53% more accurate) - Added `sentiment_analysis` + `speaker_labels` features - Cost: ~$0.02/min for transcription - Skill created: `assemblyai-transcription` (6.3KB) ### Batch Processing Strategy Duration-based triage (proven effective): - **180s+** calls first -- real conversations, highest value (2,127 calls identified) - **120s+** next -- solid calls - **90-119s** -- borderline, worth transcribing (~735 calls, ~$15 AssemblyAI) - **<90s** -- mostly junk/short, not worth transcribing (~28K CallFire calls skipped) ### CallRail Transcription Pull Script: `scripts/pull-callrail-transcriptions.mjs` - Uses CallRail LIST endpoint (250 calls/request), NOT per-call fetches - `date_range=all_time` required -- without it, CallRail defaults to recent only - 26,422 total calls, 106 API requests, under 8 minutes - Rate limited to <750 requests/hr (leaving 50 buffer) - Handles 429 rate limit responses with 60s wait + retry - Updates `call_log` by matching on `provider_call_id` - Pulls: transcription, call_summary, sentiment, lead_score, lead_explanation, speaker_percent - Normalizes sentiment to lowercase (CallRail uses "Positive", system uses "positive") - Lead classification: `lead_score >= 50` = is_lead ### Call Data Volume (as of 2026-03-10) ``` Provider Total Recording Transcribed AI Notes CallRail 24,815 12,798 12,351 24,636 CallFire 51,065 30,356 1,451 1,405 SignalWire 7,592 5,772 4,527 4,264 Twilio 19,932 0 0 0 ``` Twilio has ZERO recordings -- blocked on dead destination numbers. Can't transcribe what doesn't exist. ### Backfill Strategy (Proven, $27 total) 1. **Parse AI notes -> structured columns** ($0): 25,363 calls had notes but NULL service_needed/caller_name. Pure DB update. 2. **AI analyze already-transcribed calls** (~$4): 309 calls with transcriptions but no analysis. Text-only Claude pass. 3. **Transcribe + analyze remaining recordings** (~$23): 744 calls with recordings but no transcription. ### Spam Detection - Duration < 10s = auto-spam - Known spam caller DB (build over time) - Quick LLM classification on transcription: "Is this a real service inquiry or spam/robocall?" - Tag as spam but keep in DB (useful for analytics) ---
ExtractFactvox
May 9, 05:26 AM
## 1. SignalWire Patterns ### SDK & API Usage - **Space**: `movers.signalwire.com` - **Project ID**: `7574f05b-d072-4aa8-a2ce-77cdf24d00b5` - **Credential in DB**: `23cf6b86-52a5-4fff-bb3d-127f287e3b38` (stored in `provider_credentials` table) - **Number inventory**: 100+ active tracking numbers - **Call volume**: 5,000+ SignalWire calls imported (2,502 from CSV covering Jan 2025 - Mar 2026, plus live API fetches) ### Call Import Pattern (CSV) Script: `scripts/import_signalwire_csv.py` - Uses Supabase `service_role` key to bypass RLS - Upserts into `call_log` with `UNIQUE(provider, provider_call_id)` constraint - Fields set to NULL for CSV imports: `provider_credential_id`, `transcription`, `sentiment`, `is_lead`, `notes`, `ended_at` - Gotcha: RLS lockdown migration (`20260302100000`) removed `anon` read access -- CSV imports existed in DB but were invisible to unauthenticated queries. Silent empty result, no error thrown. ### LaML Bin Usage - Example: Bought `+18164857394` (816 KC) for Max Clean Mold Remediation - LaML bin configured to forward to `+14073050213` - Forwarding rule stored in DB with full GMB data (gmb_url, cid, niche, api_name, api_address) ### Push to SignalWire (VoiceUrl Configuration) Pattern from `api/call-flows-push.ts`: ``` 1. Load call_flow_configs + forwarding_rule + provider_credentials 2. Build handler URL: {SUPABASE_URL}/functions/v1/twiml-handler 3. POST to SignalWire LaML-compatible API: PUT https://{space}/api/laml/2010-04-01/Accounts/{project_id}/IncomingPhoneNumbers/{sid}.json Body: VoiceUrl={handler_url}&VoiceMethod=POST 4. Update push_status in DB on success/failure ``` ### SWML for AI Receptionist - AI Receptionist flow type uses SWML JSON format (not TwiML) - Excluded from call flow pipelines because SWML is a different execution model than TwiML - SWML config generated in `src/services/callFlows/adapters/signalwire.ts` (lines 100-149) - Pattern in twiml-handler: `ai_receptionist` case at line 317 returns SWML JSON response ### Outbound AI Agent Architecture (Hawkeye System) Designed but not fully live. Architecture: ``` api/outbound-call.ts (Vercel serverless) -> JWT auth -> load outbound_call row -> check DNC -> load SignalWire creds -> Render SWML template with call_log context data -> POST to SignalWire Calls.json endpoint -> Url points to outbound-agent-handler edge function supabase/functions/outbound-agent-handler/index.ts -> SignalWire fetches this when callee answers -> Reads call_id from query params -> loads rendered prompt -> returns SWML JSON supabase/functions/outbound-agent-webhook/index.ts -> Post-call webhook receiver -> Saves: ai_summary, call_outcome, duration, recording_url -> Updates status to completed/no_answer/voicemail ``` Safety constraints: - No auto-dial -- every call requires explicit user confirmation - DNC table checked server-side before every call - Rate limit: max 20 calls/hour - Time window: 9am-8pm local time only - Machine detection via SignalWire AMD - Kill switch via campaign status `paused`/`cancelled` ---
ExtractFactvox
May 9, 05:26 AM
## 3. Call Flow Architecture ### 13 Flow Types (Fully Implemented) Located in `src/services/callFlows/`: 1. **Simple Forward** -- direct dial to destination 2. **IVR Menu** -- keypress-based branching 3. **Ring All** -- simultaneous ring to multiple destinations 4. **Hunt Group** -- sequential ring through a list 5. **Time-Based** -- route by time of day/day of week 6. **Overflow** -- fallback when primary is busy/unreachable (ring timeout default 25s) 7. **Round Robin** -- rotate evenly across destinations 8. **Voicemail** -- send to voicemail 9. **Whisper** -- announce caller info before connecting 10. **Recording** -- record the call (modifier, not standalone step) 11. **Call Queue** -- hold callers in queue 12. **API Bidding** -- route to highest bidder via external API endpoint 13. **AI Receptionist** -- SWML AI agent (SignalWire only) ### TwiML Handler (Core Routing Engine) File: `supabase/functions/twiml-handler/index.ts` (~740 lines) - Receives Twilio/SignalWire POST (form-urlencoded or query params): `To`, `From` - Queries `forwarding_rules` WHERE `is_active = true` - Matches phone_number by normalized last-10 digits - Returns TwiML `<Dial>` with destination_number - Falls back to "not configured" message if no rule found ```xml <Response> <Dial callerId="{to_number}">{destination_number}</Dial> </Response> ``` ### Provider Adapters 3 adapter files for TwiML/LaML/XML generation: - `adapters/twilio.ts` -- TwiML generation - `adapters/signalwire.ts` -- LaML/SWML generation - `adapters/callfire.ts` -- CallFire XML ### Push Flow (End-to-End) ``` CallFlows.tsx -> handlePush() -> callFlowConfigService.pushToProvider(id) -> Gets JWT, POSTs to /api/call-flows-push (Vercel serverless) -> Validates auth, loads config + credential from Supabase -> Pushes VoiceUrl to Twilio/SignalWire/CallFire -> DB updates: push_status, push_error, last_pushed_at ``` Provider-specific push: - **Twilio**: POST to `api.twilio.com/.../IncomingPhoneNumbers/{sid}.json` with VoiceUrl + VoiceMethod - **SignalWire**: PUT to `{space}/api/laml/2010-04-01/Accounts/{project_id}/IncomingPhoneNumbers/{sid}.json` - **CallFire**: Not supported for VoiceUrl push (manages routing internally) - **CallRail/Lead Magicai**: Returns clear "This provider manages call routing externally" error ### Call Flow Pipelines (Designed, Not Live) Architecture for chaining flows (e.g., Whisper -> Ring All -> Voicemail): - Chain state via URL query params (stateless): `?pipeline_id=X&step=N&rule_id=Y` - 3 behavior types: - **pass-through** (whisper, recording): execute then continue - **terminal** (voicemail, ai_receptionist, simple_forward, round_robin, call_queue): call ends - **conditional** (ring_all, hunt_group, overflow, ivr_menu, api_bidding, time_based): callback on events - Recording is a modifier, not a step -- peeks ahead and merges `record=` onto next step's `<Dial>` - Max 5 steps per pipeline - Terminal flows only as last step - AI Receptionist cannot be in pipelines - CallFire excluded (no `action=` callbacks) - Decision: test basic single flows FIRST before building pipeline complexity ### Critical Safety Rule ``` NEVER modify live phone numbers, VoiceUrls, forwarding configs, or provider settings without explicit Mike approval. Call flows are OPT-IN only -- numbers must be manually assigned + flow toggled active. ``` ---
ExtractArchitecturevox
May 9, 05:26 AM
## 8. Database Schema (Key Tables) ### call_log (Source of Truth) All tabs query this: Dashboard, Leads, Categories, Folders, Calls. Key columns: - `id`, `provider`, `provider_call_id` (UNIQUE with provider) - `from_number`, `to_number`, `status`, `direction` - `started_at`, `ended_at`, `duration` - `recording_url`, `transcription`, `notes` - `sentiment`, `is_lead`, `caller_name`, `service_needed` - `gmb_name`, `niche`, `forwarding_rule_id` - `appointment_booked`, `company_hired`, `revenue_estimated` - `urgency_level`, `customer_type`, `call_outcome` - `ai_provider`, `ai_confidence` ### forwarding_rules - `phone_number`, `destination_number`, `friendly_name` - `niche`, `gmb_url`, `cid`, `api_name`, `api_address` - `provider_credential_id` -> FK - `is_active` (boolean) ### provider_credentials - `provider` (twilio, signalwire, callfire, callrail, lead_magicai) - `account_sid`, `auth_token`, `space_url` (SignalWire) ### call_flow_configs - `forwarding_rule_id` -> FK - `flow_type` (13 types) - `config` (JSONB -- type-specific settings) - `push_status`, `push_error`, `last_pushed_at` - `flow_order`, `pipeline_id` (for pipeline chaining) ### outbound_campaigns / outbound_calls / agent_templates / do_not_call - Campaign metadata, individual call records, prompt templates, blocked numbers - Part of Hawkeye outbound AI system ### text_messages - SMS/text conversations, initially from CallRail - 7,495+ rows from CallRail `recent_messages` ---
ExtractFactvox
May 9, 05:26 AM
## 7. Anti-Patterns & Lessons Learned ### RLS Silent Failures - Supabase RLS blocking queries returns empty results with NO error, not a 403. This caused the "imported 2,502 calls but can't see them" bug. Always verify authentication state before assuming data is missing. ### created_at vs started_at Confusion - Bulk sync/upsert operations set `created_at` to the insert time, not the original call time. Dashboard queries filtering by `created_at` showed "no calls for 4 days" when in reality calls existed but with wrong timestamps. Use `started_at` (the actual call timestamp) for display, not `created_at`. ### CallFire Duration Division Bug - CallFire API returns duration in seconds. The edge function was dividing by 1000 (treating as milliseconds). Everything showed 0 seconds. Always check provider-specific units. ### Category Explosion - Categories auto-derived from `call_log.niche` with zero normalization. Result: "air conditioning contractor" vs "air conditioning repair service" vs "HVAC" vs "hvac-contractor" as separate categories. Lesson: normalize/deduplicate niches at write time. ### Twilio Number Recovery - Numbers released from Twilio can be repurchased if still available. 39 released numbers were successfully repurchased. But numbers on OTHER Twilio accounts (D.Hood's, Liam's) cannot be reclaimed -- must buy replacements. ### CSV Import vs Live API Fetch - CSV imports use `service_role` key and bypass RLS -- they work for seeding historical data - Live API fetches go through the `call-activity` edge function which also uses `service_role` - BUT the dashboard queries use the authenticated client, which requires user login - These two paths have different auth requirements -- easy to have data that exists but isn't visible ### Pipeline Before Singles - Call flow pipelines (chaining Whisper -> Ring All -> Voicemail) were designed before basic single flows were ever tested live. Mike correctly chose to test singles first. Never build advanced composition on untested primitives. ### CallRail Default Date Range - CallRail API defaults to recent calls only if `date_range` param is omitted. Must explicitly pass `date_range=all_time` to get historical data. Missing this parameter caused 24,746 calls to be invisible. ### Provider Push Gotchas - CallRail and Lead Magicai don't support VoiceUrl push (they manage routing internally). The API was returning "Unknown provider" instead of a clear error. Fixed by adding explicit cases that return a human-readable "not supported" message. ### RingBA Revenue Calls Not in System - Revenue-generating calls from RingBA (HVAC via `+18445910068`) were not appearing in the call database. Separate tracking system with different number pools. Lesson: verify ALL revenue-generating number pools are registered in the system. ---
ExtractFeedbackvox
May 9, 05:26 AM
## 10. Key File Paths ``` D:\ClaudeDev\00_GITHUB\_working-on\Tools\call-sentiment-AI\ src/services/leadPipeline.ts -- recording -> transcribe -> analyze pipeline src/services/callActivityService.ts -- provider API fetching, sync logic src/services/callLogService.ts -- call_log queries for all tabs src/services/callerIntelService.ts -- caller intel extraction from notes src/services/callFlows/ -- 13 flow type adapters + registry + config src/services/callFlows/adapters/ -- twilio.ts, signalwire.ts, callfire.ts src/components/calls/HawkeyePanel.tsx -- AI chat assistant + outbound agent trigger src/components/CallFlows.tsx -- call flows UI api/call-flows-push.ts -- server-side provider push api/outbound-call.ts -- outbound AI call initiation supabase/functions/twiml-handler/ -- incoming call router (~740 LOC) supabase/functions/call-activity/ -- provider fetch + upsert supabase/functions/call-forwarding/ -- number management scripts/import_signalwire_csv.py -- SignalWire CSV importer scripts/pull-callrail-transcriptions.mjs -- CallRail bulk transcription pull ```
ExtractFactvox
May 9, 05:26 AM
## 6. Number & Carrier Management ### Provider Inventory (5 Active Providers) | Provider | Credential ID | Numbers | Notes | |----------|--------------|---------|-------| | CallFire | `763a774e` | 52 | Account: CTR Geeks / Michael Merlino, password `492eeb291f0c1c2f` | | Twilio #1 | `107f7c4c` | ~31 | Main account (AC3c132da...) | | Twilio #2 | `04e7d25f` | 7 | ezmoneywealthsystems account (AC21df195...) | | SignalWire | `23cf6b86` | 100+ | movers.signalwire.com | | CallRail | `131f8651` | 33 | Account 248285658, 68 companies (29 active), 2-year data retention limit | | Lead Magicai | (env only) | -- | Dumpster rental calls, API key in .env | ### Number Acquisition Patterns - **Twilio API purchases**: Bought 15 replacement numbers for GMBs previously on D.Hood's/Liam's accounts ($17.25/mo total for 15) - **SignalWire**: Bought +18164857394 (816 KC) for Max Clean Mold Remediation via LaML bin - **Area code matching**: Always buy numbers in the same area code as the business location (e.g., 561 for West Palm Beach, 816 for Kansas City) ### Carrier Lookup & Number Porting - Used carrier lookup to identify where 15 missing numbers lived: - D.Hood's Twilio account (7 numbers) - Liam's Twilio account (1 number) - EZ Texting/Sinch (3 numbers, mobile/nonFixedVoip) - Onvoy/Sinch (1 number, nonFixedVoip) - Strategy: buy NEW replacement numbers on Mike's Twilio, then update GMB listings ### Forwarding Rules Architecture Table: `forwarding_rules` - `phone_number` -- tracking number - `destination_number` -- where calls forward to - `friendly_name` -- GMB business name (e.g., "Big State Electricians-Dallas") - `niche` -- business category - `gmb_url`, `cid`, `api_name`, `api_address` -- GMB identity fields - `provider_credential_id` -> FK to `provider_credentials` - `is_active` -- boolean toggle Matching logic in edge function: ```typescript function enrichCallWithRule(call, rules) { const normalizedTo = normalizeLast10(call.to); const matchedRule = rules.find(r => normalizeLast10(r.phone_number) === normalizedTo); if (matchedRule) { call.destination = matchedRule.destination_number; call.gmb_name = matchedRule.friendly_name; call.niche = matchedRule.niche || ""; call.forwarding_rule_id = matchedRule.id; } } ``` ### GMB-to-Number Matching - `GMB_FINAL_LIVE.csv` (435 businesses) matched to 73 forwarding rules - 68 of 73 successfully matched with GMB data - 12 GMBs still missing logins (Wise Owl, Green Star, Prudent, Safe Flow, Choice Fire, Zoop) - 14 unmatched Twilio businesses identified as open TODO ### CallFire-Specific Issues - 12 numbers were forwarding to wrong number (`18444781558`) -- all 12 updated to correct targets - 1 number labeled "DELETE" (`+17372370725`) - 8 CallFire numbers not in spreadsheet but forwarding -- need verification - CallFire duration bug: edge function was dividing duration by 1000 when already in seconds (everything showed 0s) - CallFire recording bug: recordings looked up at wrong nested path in API response ### Twilio-Specific Issues - Application SID override on cyberdepot.us was intercepting calls - URL encoding issue: `+` sign in phone numbers needs proper encoding in TwiML URLs - 5 of ezmoney's 7 numbers were on calltrack.co (CallTrackingMetrics), 2 on Twilio demo ---
ExtractPatternvox
May 9, 05:26 AM
## 9. Infrastructure & Deployment ### Current Stack - **Frontend**: Next.js (Vite) + Tailwind + ShadCN, deployed on Vercel - **Backend**: Supabase edge functions (Deno) + Vercel serverless (Node.js) - **Database**: Supabase Postgres (project `fkevlziqywadolkektwa`, Pro plan) - **Domain**: birdseyeroi.com (Namecheap -> Vercel DNS) - **Auth**: Supabase Auth (email/password, admin only, no public signup) ### Edge Functions | Function | Purpose | |----------|---------| | `twiml-handler` | Incoming call router, ~740 lines, handles all 13 flow types | | `call-activity` | Fetch + sync calls from all providers, upsert into call_log | | `call-forwarding` | Number management + routing rule CRUD | | `outbound-agent-handler` | SWML server for outbound AI calls | | `outbound-agent-webhook` | Post-call webhook receiver | ### Vercel Serverless Routes | Route | Purpose | |-------|---------| | `api/call-flows-push.ts` | Push VoiceUrl configs to providers | | `api/outbound-call.ts` | Initiate outbound AI calls | | `api/webhooks-lbm.ts` | LBM webhook receiver (URL: dash not slash) | ### Planned: Hetzner Backend - CX41 (8 vCPU, 16GB RAM, 160GB disk) + 500GB volume = ~$42/mo - BullMQ + Redis job queue, PM2 process manager, Caddy reverse proxy - Would replace client-side AI pipeline with server-side processing - Two modes: webhook (real-time, ~30s turnaround) and cron (batch, every 15-30 min) ---
ExtractArchitecturevox
May 9, 05:26 AM
# Vox Telephony Insights — Mined from Chat Backups Extracted: 2026-05-09 Source: 370+ chat files from Call-Sentiment-AI, 21 from Side-Projects, 4 from Coding-Projects Agent: Vox (Telephony & Voice AI Lead) ---
ExtractFactvox
May 9, 05:26 AM
## 2. Voice AI Agent Design ### Agent Templates (Database-Driven) Table: `agent_templates` with `{{variable}}` placeholder system 4 seeded template types: 1. `lead_followup` -- re-engage callers who expressed interest 2. `missed_call_recovery` -- call back people who called when no one answered 3. `appointment_confirm` -- verify scheduled appointments 4. `cold_outreach` -- proactive outreach campaigns Template rendering: `agentTemplateService.ts` substitutes call_log data fields (caller_name, service_needed, gmb_name, niche) into SWML prompt templates. ### Hawkeye Panel - Chat-based AI assistant embedded in BirdsEye ROI dashboard - "Agent" button on call detail cards -> opens `DeployAgentDialog` - Shows: who's being called, which template, rendered prompt preview, from-number selector - V2 planned: parse `[ACTION:CREATE_CAMPAIGN:{...}]` blocks from Hawkeye's response stream to auto-create campaigns - V3 planned: A/B template testing, smart scheduling, multi-touch sequences (call -> SMS) ### AI Receptionist (Inbound) - Flow type `ai_receptionist` in the 13-type call flow system - Uses SignalWire `ai` verb via SWML - Cannot be chained in pipelines (SWML format incompatible with TwiML action= callbacks) - Can only be terminal (last step in a flow) ### Conversation Design Decisions - AI agent receives caller's name, service_needed, and context from original call - Post-call: summary + outcome saved back to DB automatically via webhook - Campaign page shows all outbound call history + results ---
ExtractArchitecturevox
May 9, 05:26 AM
## 5. TTS & Audio ### Recording Storage Architecture (Hetzner Backend Plan) Designed but not yet deployed: ``` Provider webhook/cron -> Hetzner Server -> Download mp3 -> /data/recordings/{provider}/{date}/{call_id}.mp3 -> Transcribe (AssemblyAI or local Whisper) -> AI analyze -> Spam filter -> Save to Supabase -> Save mp3 to local disk ``` Storage math: - Average mp3: ~500KB/min - 100 calls/day x 2 min avg = ~100MB/day - 30 days = ~3GB/month - 500GB volume = ~14 months before cleanup ### Processing Modes 1. **Webhook (real-time)**: SignalWire/Twilio send webhook on call complete -> ~30 sec turnaround 2. **Cron (batch)**: Every 15-30 min, poll all providers. Good fallback for CallFire (no webhooks) ### AI Models Used - **Transcription**: AssemblyAI Universal-2 (primary), local Whisper (planned alternative) - **Analysis**: Claude Sonnet 4.6 (primary), GPT-4.1 (secondary/hybrid) - Both models available via `getBestAIProvider()` selection ### Voice Cloning - Mike's voice cloned via Fish Audio API (separate `merlino-voice` skill) - Not yet integrated into call flow system ---
ExtractArchitecturevox
May 9, 05:26 AM
## 7. Structured Data / Schema ### Schema Stack (Mike's confirmed ranking signal hierarchy) Q&A > FAQ > LocalBusiness+@ID > AggregateRating > VideoObject ### Schema Found on Flat Fee Cleaners (95/100 — already strong) - LocalBusiness + HousekeepingService - FAQPage (5 pages) - Article (3 blog posts) - BreadcrumbList (blog posts) - Offer/Service (Move-Out page) **Missing on that site:** - Organization schema (homepage) - WebSite schema with sitelinks search - Service schema (individual service pages) - Review schema (individual reviews, not just AggregateRating) - ImageObject schema ### Schema Audit Process - Verify per-page schema in page.tsx/layout.tsx source - Check data consistency: review count + rating must match across all schema instances - Validate with Google Rich Results Test - Inject site-wide schema in root `layout.tsx` - BreadcrumbList: Home → [Category] → [Page Name] pattern ### SEORockstars 2014 (Josh Bachynski — State of SEO) - Hummingbird entity framework — schema/microdata critical - CTR optimization cited as primary ranking lever - 7-link ranking strategy presented - Panda/Penguin recovery via content quality + entity signals ---
ExtractArchitecturemerlin
May 9, 05:25 AM
## 2. CTR Optimization ### CTRify Campaign Setup (7-Phase System) Derived from ctr-ops skill and chat context. **Account rule:** All Google platforms (GSC, GA) must use `team@merlinomarketing.com`. **Phase sequence:** 1. GSC verification — URL prefix method, HTML tag, paste only the `content="..."` value (not full meta tag) 2. GA property — under "CTRify Sites" parent account, stream name "CTRify Website", www prefix on domain 3. Website design — every site must have unique theme/colors/header/footer; never reuse defaults across sites 4. SEO settings + author — niche-matched AI-generated bio + AI profile image 5. Sitemap submission — use `sitemapindex.xml` over plain `sitemap.xml`; may need 2–3 resubmits 6. Alpha Index Checker — `Sitemap Extractor` → scrape all URLs → enable "Send to Omega Indexer" toggle → create campaign 7. Omega Indexer — receives URLs from Alpha; monitor: In Queue → Processing → Indexed; target 7–15 days **Key analogy:** Alpha = breadcrumbs (Google discovers pages). Omega = noise + activity (Google pays attention and indexes). **Anti-patterns:** - Using domain property in GSC instead of URL prefix - Pasting full `<meta>` tag instead of just the code value - Same default design across multiple CTRify sites - Not enabling "Send to Omega Indexer" in Alpha campaigns - Skipping GA↔GSC linking (organic search data won't appear) - Author bio not matching the site niche ### CTR Signal Strategy (4-Pillar Campaign Model) Derived from ctr-mastery skill. **The cardinal rule:** Quality > quantity. 20 clicks @ 3 min dwell time beats 200 bounced clicks. **Volume formula:** ``` Daily Traffic Target = (Monthly Search Volume × 0.10) / 30 Start at 50% of target; scale 20% weekly if rankings improve ``` | Threshold | Action | |-----------|--------| | < 10% of search volume | Safe, conservative | | 10–20% | Optimal range | | 20–30% | Aggressive, monitor closely | | > 30% | DANGER — reduce immediately | **4 Pillars:** 1. **Branded Traffic (Weeks 1–2):** Brand name, brand + city, brand + phone/reviews/hours/directions. 10–20 clicks/day. Dwell 2–4 minutes, navigate 2–3 internal pages, click-to-call or get directions. 2. **Entity Integration (Weeks 3–4):** Brand + service, brand + industry entity, city + service + brand. 20–40 clicks/day. 3. **Keyword Expansion (Weeks 5–8):** "best [service] in [city]", "[service] near me", "top rated [service] [city]", emergency/affordable variants. 30–75 clicks/day. Vary positions clicked (not always #1). 4. **Authority Domination (Ongoing):** Maintain consistent volume, seasonal adjustments. ### Google Patents — CTR as a Ranking Signal Key patents confirmed from research (2026-01-10): **US8738436B2** (Yahoo/2014) — CTR prediction as a ranking input. 12-feature model including: appearance, attention capture, freshness, branding, position. Documents with similar titles, authors, publishers, and types used to normalize CTR. **US10229166B1** — Long click to short click ratio (LC|C metric). Position-independent measure of dwell time given click-through. Short clicks = dissatisfaction signal. **US20080275882A1 / US7899815B2** — Pogo-sticking benchmarks. Pre-pogosticking (results clicked before) and post-pogosticking (results clicked after) tracked. Used to adjust search algorithm ranking. Average rates measured per search result, per rank position. **US20180011854A1** — User engagement signal types: - Long dwell clicks: >30s general, 2s images, 15s mail - Reformulation-based negative signals - Abandonment-based signals - Normalized + aggregated scores for ranking models **Click fraud detection thresholds (US20080162475A1):** - 15 clicks/minute (singular) triggers alert - 8 clicks/minute (extended) triggers alert - 500 clicks/day threshold - Three fraud types: competitor click abuse, self-clicking, incentivized users **Bot detection signals (US20230316124A1):** Session-based click activity, topology-aware anomaly detection, distinguishing human vs. automated behavioral patterns. ---
ExtractFactmerlin
May 9, 05:25 AM
## 6. Data & API Patterns ### DataForSEO Usage Patterns From Tommy's domain knowledge and audit machine context: - **Keywords API:** $0.075/task — always batch to 1,000/request to minimize cost - **SERP API:** use `/live/advanced` ($0.002) for richest data - **GMB endpoints:** async only (not synchronous) - **Content Analysis `/live`:** synchronous endpoint **Competitive analysis rule:** Exclude Yelp, directories, citations, Reddit — only real business sites count. **22-endpoint audit pipeline (from neil-landson-audit project):** Full Merlino-style audit requires 22 DataForSEO API endpoints + 16 skills + 3-round QA. Static data only — no search snippet guessing. ### Google Patents Research (SEO-Research folder, 2026-01-10) Multiple patent research sessions produced these inventories: **User Behavior & Click Patents: 111 patents across 8 categories** | Category | Count | |----------|-------| | Personalized Search & Recommendations | 25 | | Click-through Rate & Click Data | 20 | | User Intent Modeling | 18 | | User Engagement Signals | 14 | | Behavioral Signals for Ranking | 12 | | Dwell Time & Session Data | 10 | | A/B Testing for Search | 7 | | User Satisfaction Prediction | 5 | **Content Quality Patents: 153+ patents across 16 categories** Key categories: Site Quality (12), Duplicate Detection (13), Freshness/Temporal (6), Author/Publisher Quality (6), Content Classification (35), Spam Detection (14), Ranking & Relevance (24), Trust & Authority (4) **Local Search Patents: 50+ patents** Key signals: user actions on maps, location prominence scoring (not just distance), implicit local intent detection, localness scores for chain business identification **Top 10 most critical content quality patents:** 1. US9195944B1 — Scoring site quality (foundational) 2. US8442984B1 — Website quality signal generation (human raters) 3. US20140280011A1 — Predicting site quality 4. US7533092B2 — Link-based spam detection 5. US8799236B1 — Duplicate content detection 6. US7797316B2 — Document freshness determination 7. US8150842B2 — Author reputation scoring 8. US7788265B2 — Taxonomy classification 9. US8965883B2 — User-generated content ranking 10. US8818995B1 — Trust-based ranking **Key local ranking patents:** - US8312010B1 — Local business ranking using mapping information (user actions on maps) - US8046371B2 — Location prominence scoring (not just distance) - US8171048B2 — Location sensitivity factor varying by topic/query type - US8200694B1 — Implicit local query identification - US10229166B1 — Long click vs short click ratio as ranking signal ### PAA Research Pattern From Flat Fee Cleaners research (2026-02-14): PAA questions clustered into: - Service-related (duration, what's included) - Pricing & value (cost, flat-fee vs. hourly) - Trust/credentials (are cleaners licensed, insured) - Local-specific (Sarasota area, neighborhoods) DataForSEO People Also Ask endpoint used to pull live PAA data per keyword. ### PAA Infographic Pipeline (Karma Movers, 2026-02-18) - 6 PAA questions → 6 infographics via Gemini CLI - Rate limit: 10 requests/minute for `gemini-2.0-flash-exp` - 3s pause between requests (increase to 60s after 429 error) - Output: ~850–980KB per infographic PNG - Stored in `public/images/infographics/` ---
ExtractPatterntommy
May 9, 05:25 AM
## 3. Analytics & Reporting ### GA4 Setup Pattern (CTRify / WordPress Sites) - Account: `team@merlinomarketing.com` - Parent account: "CTRify Sites" (create all properties under this account) - Property name: domain name (e.g., `herculesaffordablemovers.com`) - Data stream: Web, www prefix, stream name "CTRify Website" - Install gtag manually; test installation before confirming - Link GA to GSC: Admin → Product Links → Search Console Links (data flows forward only, 24–48h to appear) - After linking, publish "Google Organic Search Traffic" report in GA → Reports → Library ### WordPress GA4 Setup - Google SiteKit plugin - Connect Google account, enable Search Console + Analytics + AdSense modules - Cross-reference SiteKit dashboard with GA4 directly ### GMB Database Management (Domain Portfolio) From domain-portfolio-dashboard project (2026-03-01): - **493 unique GMB records** after deduplication (was 540) - CID URL completeness: 78% (key data point — 22% of records have no CID) - Phone completeness: only 48% — major gap - WP login: only 14% — major gap - Dedup rule: same name = same business; `?cid=` URL wins over `goo.gl/maps/` short URL - Niche breakdown: Roofing 140, Moving 77, HVAC 28, Dumpster 22 ### Reporting Dimensions Tracked - Status: active/inactive (279 active vs 111 inactive in GMB portfolio) - Completeness scores per field (cid_url, website, domain, phone, gmb_email, wp_login, author, niche) - Niche distribution - Duplicate detection by CID URL and by name ---
ExtractPatternmerlincarlos
May 9, 05:25 AM
# Tommy — Technical SEO Insights Extract **Source Folders:** SEO-Research, SEO-Rockstars, Domain-Portfolio **Compiled:** 2026-05-09 **Agent:** Tommy (Technical SEO + Data Lead) ---
ExtractFacttommy
May 9, 05:25 AM
## 1. Technical Audit Patterns ### Next.js Site Audit Checklist (22-Check Framework) Derived from Flat Fee Movers Sarasota audit (2026-02-15, 22/22 PASS). **Infrastructure (5 checks)** - `robots.ts` exists with correct Allow/Disallow rules + sitemap reference - `sitemap.ts` or `sitemap.xml` covers all pages (prioritized: homepage 1.0, services 0.9, blog/core 0.8, areas 0.7, utility 0.6) - Sitemap includes `changeFrequency` values (weekly/monthly/yearly per page type) - `next.config.ts` has `remotePatterns` configured for all image domains - No orphan pages in sitemap (compare URL count to route count) **Meta Tags (7 checks)** - Unique title per page — primary keyword near beginning, 50–60 chars - Unique meta description per page — 150–155 chars max - No duplicate titles or descriptions across pages - Titles include primary keyword + location modifier - Brand name at end of title only **Canonical & OG (7 checks)** - Root layout has `metadataBase: new URL(brand.website)` - Every page exports `alternates.canonical` - `openGraph.title`, `openGraph.description`, `openGraph.images` (absolute URL) on every page - `openGraph.type: 'website'` on homepage; appropriate types on subpages - `twitter` card object: `summary_large_image`, title, description, creator, images **Heading Hierarchy (4 checks)** - Exactly ONE H1 per page — contains primary keyword - No skipped heading levels (H1 → H2 → H3, never H1 → H3) - H2s are descriptive and keyword-relevant, not generic ### Common Failures Found (Flat Fee Cleaners Audit, Score 78/100) | Category | Score | Issue | |----------|-------|-------| | Sitemap + robots.txt | 0/100 | Both returning 404 — nothing submitted to GSC | | Canonical URLs | 30/100 | No canonical tags; Vercel subdomain + production domain both indexable | | OG Images | 75/100 | og:title/description present but no og:image, twitter:image | | Meta Titles | 82/100 | 5 of 7 pages over 60 chars; brand name consumed half the budget | | Core Web Vitals | 75/100 | No RUM; Unsplash images adding external domain latency | **Quick Win ROI estimates (Flat Fee Cleaners):** - Canonical tags: 2 hours → prevent duplicate content penalties - sitemap.xml: 2 hours → immediate indexing improvement - robots.txt: 30 min → crawl guidance - Trim meta titles: 3 hours → better SERP CTR - og:image 1200x630: 4 hours → social CTR - Total: ~11.5 hours → estimated +15–25% organic traffic in 60 days ### Internal Linking Audit Framework (16-Page Matrix) Derived from Flat Fee Cleaners interlinking audit (2026-02-14). **Orphan page definition:** Zero inbound links from body content (header/footer nav excluded). **Common gaps found:** - Blog-to-blog cross-links: ZERO (most common failure — every blog should link to 2–3 related posts) - Service pages to blog: ZERO (every service page should link to its PAA/educational blog content) - Service page cross-links: ZERO (related services never reference each other) - Homepage to blog: ZERO ("Latest from Blog" section missing) - Area pages to services: ZERO (area pages should link to all 3+ services) - Pricing page to service detail pages: ZERO - FAQ to service/blog pages: ZERO **Anchor text problems found:** - All three service pages used only generic CTA anchor text ("Get Your Free Quote") - Pricing page used `<a href>` instead of Next.js `<Link>` component **What a passing Next.js site looks like (Flat Fee Movers, 23/23 PASS):** - `brand.services` array drives all service links — no hardcoded routes - Services appear in: header dropdown, homepage grid, footer column - Area pages include `adjacentAreas` array for cross-area linking - Blog posts include `relatedPosts` filtered by service category - All dynamic routes resolve from brand data source (`brand.ts`) - `target="_blank" rel="noopener noreferrer"` on all external links - All pages reachable within 3 clicks of homepage ### Image Audit Patterns (Flat Fee Cleaners, 2026-02-14) **Critical findings:** - 100% of images served from Unsplash (external dependency, adds LCP latency) - 0 local images in `/public` folder - All images use raw `<img>` tags, not Next.js `<Image>` component - No `width` or `height` props on any image — CLS risk - No `og:image` set (no social sharing visual) - Alt text coverage was 100% (strong), but alt text was keyword-rich without stuffing **Anti-pattern confirmed:** Never use Unsplash or stock photo services. Use client-provided images, AI-generated (FAL AI/Gemini CLI), or CSS gradients as placeholders. ---
ExtractPatterntommymerlin
May 9, 05:25 AM
## 4. Indexation & Crawling ### Alpha Index Checker + Omega Indexer Workflow (Primary indexation stack — from ctr-ops skill) **Alpha Index Checker (alphaindexchecker.com):** 1. Login → Dashboard → Sitemap Extractor → Create New Extractor 2. Paste domain URL → Proceed → auto-scrapes all URLs from sitemap 3. Wait for "Finished" status 4. Go to Campaigns → name = domain name → select extracted URLs 5. CRITICAL: Enable "Send to Omega Indexer" toggle before creating campaign 6. Monitor: Total URLs, Indexed count, Not Indexed count, refresh periodically **Omega Indexer (omegaindexer.com):** 1. Login → Dashboard v2 (newer interface) 2. Domain appears automatically from Alpha 3. Status flow: In Queue → Processing → Indexed 4. Timeline: "Links appear on search engines within 7–15 days" 5. Filter by status, search by URL **Monitoring cadence:** - First check: 2–3 hours post-campaign creation - Second check: next day - Ongoing: weekly until all pages indexed - Re-run if new pages added ### Sitemap Strategy - Prefer `sitemapindex.xml` over plain `sitemap.xml` for complete coverage - In Next.js: implement as `src/app/sitemap.ts` (server-generated) - 84-URL sitemap structure for moving site: 1 homepage + 14 services + 23 areas + 30 blog posts + 10 core pages + 3 hubs + 3 utility - Submit to both GSC and Bing Webmaster Tools separately - Re-submit after major site changes ### robots.txt Essentials - Disallow: `/admin/`, `/api/`, `/_next/` - Include sitemap reference at bottom - Do NOT block GPTBot, PerplexityBot, ClaudeBot — these have significant GEO/AI visibility impact - Blocking Google-Extended does NOT block Googlebot search indexing — only affects AI training data and potentially AI Overviews ### Crawl Depth Rule - All key content within 3 clicks of homepage - Pages at depth 4+ receive less crawl budget and less AI citation probability - Service pages: 1 click (homepage → service grid) - Area pages: 2 clicks max - Blog posts: 2 clicks max (homepage → blog hub → post) - All utility pages: 1 click (header/footer) ### GSC Property Setup - Domain method: requires DNS TXT record (preferred for full-domain coverage) - URL prefix method: use for CTRify sites (HTML tag verification) - Submit sitemapindex.xml, not just sitemap.xml - Monitor Coverage report for soft 404s, excluded pages, redirect issues ---
ExtractPatterntommy
May 9, 05:25 AM
## Source Index | File | Key Patterns Extracted | |------|----------------------| | SEO-Research/2026-02-15/2223-technical-seo-audit | 22-check Next.js audit framework, Flat Fee Movers 22/22 PASS | | SEO-Research/2026-02-14/1659-seo-audit-flat-fee-cleaners | 78/100 score breakdown, critical failures list, ROI estimates | | SEO-Research/2026-02-14/1656-interlinking-audit | 16-page link matrix, orphan pages, anchor text gaps | | SEO-Research/2026-02-14/1656-image-audit | Unsplash anti-pattern, 21 images inventoried, CLS risks | | SEO-Research/2026-02-15/2227-internal-linking-navigation | 23/23 PASS next.js site audit, silo structure model | | SEO-Research/2026-01-10/1259-ctr-click-patents | 20+ CTR patents, pogo-sticking, dwell time, fraud detection | | SEO-Research/2026-01-10/1157-user-behavior-patents | 111 patents, personalization/CTR/intent/engagement breakdown | | SEO-Research/2026-01-10/1151-content-quality-patents | 153+ patents, Panda signals, duplicate detection, freshness | | SEO-Research/2026-01-10/1149-local-search-patents | Local prominence scoring, implicit intent, location sensitivity | | SEO-Research/2026-02-18/0112-paa-infographics | Gemini rate limits, PAA infographic pipeline | | SEO-Rockstars/2025-12-16/0116-2014-transcripts | Josh Bachynski CTR optimization, Hummingbird entity framework | | Domain-Portfolio/2026-03-01/1927-gmb-database | 493 GMB records, dedup logic, niche distribution |
ExtractFacttommysherlock
May 9, 05:25 AM
## 8. Anti-Patterns (Technical Approaches That Failed) ### Indexation Anti-Patterns - Launching a site without sitemap.xml or robots.txt (Flat Fee Cleaners launched to production with both returning 404) - Submitting plain sitemap.xml when sitemapindex.xml is available - Not enabling "Send to Omega Indexer" in Alpha campaigns — eliminates the forced indexation benefit - Blocking AI crawlers (GPTBot, PerplexityBot) in robots.txt — confirmed GEO impact ### Canonical Anti-Patterns - No canonical tags when site is live on both Vercel subdomain AND production domain — causes duplicate content penalties - Trailing slash inconsistency without canonical enforcement - UTM parameters creating duplicate URLs without canonical handling ### CTR Campaign Anti-Patterns - Sending > 30% of monthly search volume daily — triggers bot detection - 500+ clicks/day crossing fraud detection threshold - All clicks going to position #1 only — unnatural pattern - Zero dwell time / immediate bounce — signals dissatisfaction - Same IP or device pattern for all clicks — topology-aware bot detection ### Image Anti-Patterns - 100% Unsplash external images — external domain latency, dependency risk, NEVER use per agency rules - Raw `<img>` tags instead of Next.js `<Image>` — no CLS protection, no srcset - Images without width/height props — CLS risk confirmed - Missing og:image — social shares show no visual ### Internal Linking Anti-Patterns - Generic anchor text ("click here", "learn more") across all CTAs - Using `<a href>` instead of Next.js `<Link>` component on pricing/conversion pages - Blog posts with ONLY breadcrumb links back to homepage and blog index (dead-end pages) - FAQ page with zero links to service or blog content - Service pages with zero cross-links to other services ### Schema Anti-Patterns - Rating/review count mismatch between AggregateRating schema and visible page content - Schema injected only in layout.tsx with no page-specific schema overrides - Missing BreadcrumbList on blog posts (breaks rich result eligibility) ### Analytics Anti-Patterns - CTRify sites using wrong Google account (must be `team@merlinomarketing.com`) - Creating GA property under wrong parent account (must be under "CTRify Sites") - Skipping GA↔GSC linking — organic search data never appears in Analytics - Reusing same CTRify design template/color/header across multiple sites — signals pattern to Google ---
ExtractDecisioneinstein
May 9, 05:25 AM

Showing 150 of 115