# A way to reach you, in plain text: the contact signals the Mega Analyzer looks for

Four of the Mega Analyzer&#39;s five contact rows only go red on a local business page: tel: link, phone, address and hours. What each pattern accepts, and what it misses.

Author: J.A. Watte
Published: September 21, 2026
Source: https://jwatte.com/blog/blog-mega-analyzer-visible-contact-signals/

---

Five rows on the Mega Analyzer's Trust + Conversion completeness card sit under one heading, "Contact + conversion mechanics," and four of them share a gate. **mailto: link or /contact page** is the row that never gets an exemption. **Visible physical street address**, **tel: link present (click-to-call)**, **Visible phone number in body text** and **Visible hours of operation** turn from blue information rows into red failures the moment the page declares itself a local business. What all five are really measuring is narrower than "do you have contact info": whether a person, a quality rater or a program reading your HTML can find a route to a human in text it can parse, without opening an image, a PDF or a map embed.

## What the check actually tests

**The gate first.** The analyzer collects every `@type` in the page's JSON-LD and tests each against a list of 130 LocalBusiness-family names (LocalBusiness, Service, Restaurant, Hotel, Motel, SelfStorageFacility, MedicalBusiness, Dentist, Plumber, Electrician, HVACBusiness, RealEstateAgent, LegalService, Store and the rest of schema.org's LocalBusiness tree), plus a suffix rule for unlisted subtypes ending in Business, Service, Store, Salon, Spa, Hotel, Gym, Shop, Agency, Center and a few others. If any type matches, or if the page's business vertical (read from schema types and keywords in the page copy, or set by you in the vertical override) starts with Local- or YMYL-, the page is "local-like." On a local-like page the four gated rows render as pass or fail, a red ✗ on a miss. Everywhere else they render as information rows, a blue ℹ on a miss, and do not count against the fail total.

One twist: the address row feeds the classifier. When no earlier vertical rule matches, a page that passes the address row by any route is classified Local-Service, so a street address in the body copy of an otherwise generic page flips the other three rows from blue to red. A page whose schema declares it a publication, an application or a personal ProfilePage is reset out of that.

**mailto: link or /contact page.** Always pass or fail. Green when the fetched document contains any `<a>` whose `href` starts with `mailto:`, or any `<a>` whose `href` contains the string `/contact` in any letter case. That second test is a substring match on the raw attribute value: `/contact/`, `/contact-us/`, `/contacts/` and `/contact.html` all pass. A relative link written as `contact.html` with no leading slash does not, and nothing checks that the link points at your own domain, so a footer link to a parent company's contact page passes too. On a miss the detail line reads "Neither a mailto: link nor an internal /contact page" followed by "users cannot reach you." What does not trip it: a contact form (a `<form>` exposes no `href`), an email address typed as plain text without a `mailto:` wrapper, an address assembled by JavaScript to defeat harvesters, and a "Contact" button that opens a modal.

**tel: link present (click-to-call).** Any `<a href="tel:...">` anywhere in the document, header and footer included. The row does not inspect the number after `tel:`, so `tel:5550100` passes it as readily as `tel:+1-208-555-0100`.

**Visible phone number in body text.** A regular expression runs over the body text plus the footer text and passes on `(208) 555-0100`, `208-555-0100`, `208.555.0100`, `208 555 0100`, a bare `2085550100`, and international forms such as `+1 208 555 0100` or `+12085550100`. A seven-digit number with no area code fails. "Body text" is the page with `script`, `style`, `nav`, `header`, `footer`, `aside`, `noscript`, `form`, anything with `role="navigation"` or `role="banner"`, and the usual cookie and legal wrappers removed; the text of `footer`, `.site-footer`, `.footer` and `[role="contentinfo"]` is then appended back. So a number printed in the footer counts. A number that lives only in a header top bar does not, because the header is stripped and never re-added; wrapping it in a `tel:` link satisfies the tel: row, not this one.

**Visible physical street address.** Three routes to green, and any one is enough:

1. A full US address on one run of body text: a number, a capitalized street name, a city, a two-letter uppercase state and a five-digit ZIP, as in `123 Main St, Twin Falls, ID 83301`.
2. A street line somewhere in the body (a number, one or more words of three or more characters that start with a letter, in any case, then one of Street, Avenue, Boulevard, Road, Drive, Lane, Way, Highway, Parkway, Court, Place, Circle, Terrace, Trail or Square, spelled out or in the usual abbreviation), together with either a five-digit number or a spelled-out state name (or D.C., or Ontario, Quebec, British Columbia, Alberta) somewhere else in the body. `123 Main St` on one line and `Twin Falls, Idaho` on another passes this way.
3. A `PostalAddress` node anywhere in the JSON-LD, nested at any depth, with at least one of `streetAddress`, `postalCode` or `addressLocality` filled in.

This is the row where the details bite, and I ran the analyzer's own expressions against a set of addresses to be sure. `123 E Main St, Twin Falls, ID 83301` fails both text routes: the single-letter directional is too short for the street-name pattern, and the full-address pattern wants at least two characters in the first word after the number. `123 East Main St` passes both. `123 E. Main St` passes only the full one-line pattern; the street-line pattern wants three characters in that word too, and `E.` is two. `450 2nd Ave` fails, because the word after the house number has to start with a letter (`2nd` starts with a digit; lowercase `main st` would pass the street-line route). `PO Box 120` fails both text routes as well; this row wants a street. Every one of those is rescued by route 3, which is why the JSON-LD step in the fix section is not optional.

The other surprise: unlike the phone and hours rows, the two text routes read the body text only. The footer is not appended for the address test, so a plain-text address that appears nowhere but the footer passes only if the JSON-LD also carries it. The fail detail on a local-like page reads "For local / bricks-and-mortar businesses, render the address in plain text so Google Maps + Apple Maps can parse it." On any other page it reads "Optional. Only required for sites with a physical service address."

**Visible hours of operation.** Same body-plus-footer text as the phone row. Passes on a day followed by a time range (`Mon to Fri 9am to 5pm`), a bare time range (`8:00 AM to 8:00 PM`), `24/7`, `open 24 hours`, `by appointment only`, or the quoted string `"openingHours"` or `"openingHoursSpecification"` anywhere in the raw HTML, which in practice means a JSON-LD key (a microdata `itemprop="openingHours"` satisfies it too).

None of the five rows judges whether the phone on the page matches the one on your Business Profile, whether the mailbox behind the `mailto:` is monitored, or whether the address is formatted the same way on Yelp. Those are what [NAP Consistency](/tools/nap-consistency/) is for. And the [Trust Signal Surface Audit](/tools/trust-signal-surface-audit/) fetches your `/contact` page and looks for an address and phone there, which the Mega Analyzer, working on the one URL you gave it, does not.

## Why it matters

Google's Search Quality Rater Guidelines (the September 11, 2025 edition) spend a subsection, 2.5.3, on finding contact information, and describe the rater's method: "start with the homepage. Look for a 'contact us' or 'customer service' link." That is the behavior the mailto/contact row imitates. The same section says contact and customer service information "are extremely important for websites that handle money, such as stores, banks, credit card companies, etc." Section 4.5.1 goes further: "Any site that handles personal, private or sensitive data must provide extensive contact information," and YMYL pages "with absolutely no information about the website or content creator should be rated Lowest." Section 5.5 adds that pages with payment functionality "should receive a Low rating if there is an unsatisfying amount of customer service information or contact information." That is why the gate treats a YMYL- vertical the same way it treats a declared LocalBusiness: raters are told to demand more from both.

The same guidelines are the reason the gate exists at all. They allow that "personal websites may omit personal contact information such as an individual's home address or phone number." An author site or a software tool with no street address is not hiding anything, and a red address row on it would be a false finding.

For a local business the reasoning is mechanical rather than reputational. Google's Local Business structured-data documentation lists exactly two required properties, `name` and `address`, and says of `telephone`: "Be sure to include the country code and area code in the phone number." The Business Profile guidelines ask for "a precise, accurate address," say "P.O. boxes or mailboxes located at remote locations aren't acceptable," ask you to "Use a local phone number instead of a central call center helpline number whenever possible," and prohibit numbers or URLs that "redirect or 'refer' users to landing pages or phone numbers other than those of the actual business." Your website is the thing the listing points at. If the address and phone on it live inside a JPEG, a PDF or a JavaScript map widget, nothing that reads the page as text can compare them to the listing, and that includes a Business Profile reviewer, an AI agent fetching your homepage, and the Mega Analyzer. The "Street" versus "St." problem, where site and listing disagree on formatting, is a separate defect; the NAP Consistency post linked below covers it.

Outside local search, the Trust Project's eight Trust Indicators for news publishers make the same point from the reader's side. Best Practices asks "Who funds the site? What is its mission?" and Actionable Feedback asks whether readers can "provide feedback that might provoke, alter or expand a story." A reachable human is the precondition for both.

One more reason most online-only businesses have an address to publish even when they think they do not: the FTC's CAN-SPAM guide says every commercial email "must include your valid physical postal address," which can be a street address, a registered post office box, or a private mailbox at a commercial mail receiving agency. If you send a newsletter, that line already exists. Put it in the footer: the address row reads body text only, so a footer address does not trip the classifier twist above and turn the phone and hours rows red on a site that is not local.

## How to fix it

**Step 1: build a /contact/ page and link it from the header or footer.** The link alone turns the mailto/contact row green, but give the page real content. Use a `mailto:` link (RFC 6068) and a `tel:` link in the global form RFC 3966 requires: "Globally unique numbers are identified by the leading '+' character," and "All phone numbers MUST use the global form unless they cannot be represented as such." Hyphens and dots are allowed inside the URI as visual separators that "merely aid readability"; spaces are not. Put the human-formatted number in the link text so the visible-phone row passes on the same element.

```html
<h1>Contact Example Plumbing</h1>
<p>Email <a href="mailto:hello@example.com">hello@example.com</a>
   or call <a href="tel:+1-208-555-0100">(208) 555-0100</a>.</p>
<p>Shop: 123 East Main St, Twin Falls, ID 83301.<br>
   Open Monday to Friday, 8:00 AM to 5:00 PM.</p>
```

**Step 2: put the address in the footer inside an `<address>` element, and match the listing character for character.** The footer is where people and Maps reviewers look, and the phone and hours rows read it. Copy the address exactly as it appears on your Google Business Profile: same abbreviation, same suite format, same ZIP. Spell out a single-letter directional (`East`, not `E`); the street-line pattern needs three characters in every word of the street name, and `E.` survives only the full one-line form.

```html
<footer>
  <address>
    Example Plumbing<br>
    123 East Main St<br>
    Twin Falls, ID 83301<br>
    <a href="tel:+1-208-555-0100">(208) 555-0100</a><br>
    <a href="mailto:hello@example.com">hello@example.com</a>
  </address>
  <p>Mon to Fri 8:00 AM to 5:00 PM</p>
  <nav><a href="/contact/">Contact</a> <a href="/about/">About</a></nav>
</footer>
```

**Step 3: add a PostalAddress to the LocalBusiness or Organization JSON-LD.** This is the route that covers every address the text patterns miss, and it is what the homepage needs when the plain-text address lives only in the footer. The shape below is the LocalBusiness node that [Schema Fix Bundle](/tools/schema-fix-bundle/) emits for its LocalBusiness page type, lifted out of its `@graph`, with the placeholders filled in, the subtype narrowed and the placeholder `aggregateRating` dropped (never invent one):

```json
{
  "@context": "https://schema.org",
  "@type": "Plumber",
  "@id": "https://example.com/#localbusiness",
  "name": "Example Plumbing",
  "url": "https://example.com/",
  "image": ["https://example.com/images/shop-front.jpg"],
  "telephone": "+1-208-555-0100",
  "email": "hello@example.com",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "123 East Main St",
    "addressLocality": "Twin Falls",
    "addressRegion": "ID",
    "postalCode": "83301",
    "addressCountry": "US"
  },
  "openingHoursSpecification": [
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
      "opens": "08:00",
      "closes": "17:00"
    }
  ],
  "geo": { "@type": "GeoCoordinates", "latitude": 42.5558, "longitude": -114.4701 },
  "priceRange": "$$",
  "sameAs": ["https://maps.google.com/?cid=1234567890123456789"]
}
```

schema.org's PostalAddress defines `streetAddress`, `addressLocality`, `addressRegion`, `postalCode`, `addressCountry`, `postOfficeBoxNumber` and `extendedAddress`. The analyzer passes when `streetAddress`, `addressLocality` or `postalCode` is present; `addressRegion` alone does not count. Google's guide asks you to fill in as many as apply. The `openingHoursSpecification` array turns the hours row green on its own, and the `telephone` value is the same string you put after `tel:`.

**Step 4: do not stop at the form.** A contact form is fine to keep, but it is invisible to every one of these rows and to any reader that cannot run your form handler. Give the page a `mailto:` and a `tel:` next to it.

**Step 5: verify from three angles.** Re-run the Mega Analyzer and check that all five rows are green together. Then run [Trust Signal Surface Audit](/tools/trust-signal-surface-audit/), which fetches `/contact` and looks for an address and phone on that page specifically. Then paste the footer address and phone into [NAP Consistency](/tools/nap-consistency/) alongside the Business Profile, Apple, Bing, Yelp and Facebook versions and clear every formatting diff it reports.

## When to leave it alone

If the four gated rows are blue on your report, your page is not local-like, and blue is the correct answer. A publication, a software tool, a remote consultancy or a personal author site does not need a street address on the homepage, and publishing a home address to satisfy a checkbox is worse than the blue row. The rater guidelines explicitly permit that omission for personal sites.

A service-area business is the harder case. A plumber who works out of a home and has hidden the address on the Business Profile still declares `Plumber` in JSON-LD, so the address row is red. Do not publish the home address. Emit a `PostalAddress` with `addressLocality`, `addressRegion` and `addressCountry` only, add `areaServed`, and leave `streetAddress` out. The analyzer's JSON-LD route accepts a locality-level address, and the Business Profile guidelines ask for an address "and/or service area," so the service area is the honest half to publish.

The mailto/contact row has no gate, and the one situation to think twice about is an inbox nobody reads. A `mailto:` to an unmonitored address passes the row and fails the rater who tests it. If you cannot commit to answering email, link the `/contact/` page (which also passes the row) and put the phone and the address there instead. The same goes for a `tel:` link to a central call center when the guidelines' preference for a local number applies to you; wire it to the number that rings at the location.

And if you already pass because a footer link points at a parent company's `/contact` page, that green row is not yours. Picture a twelve-property operator with one corporate contact page: all twelve property sites pass this row by linking to it, and not one of them tells a guest which desk to call. Give each location its own contact page with its own number. That is the pattern The $100 Network is built around: one owner, several small sites, each one reachable on its own.

## Fact-check notes and sources

- **Source**: https://static.googleusercontent.com/media/guidelines.raterhub.com/en//searchqualityevaluatorguidelines.pdf (General Guidelines, September 11, 2025 edition). Section 2.5.3 establishes the rater's homepage-first search for a contact link, the "handle money" standard, and the personal-site exemption; section 4.5.1 the "extensive contact information" rule for sites handling sensitive data and the Lowest rating; section 5.5 the Low rating for payment pages with unsatisfying contact information.
- **Source**: https://developers.google.com/search/docs/appearance/structured-data/local-business establishes that `name` and `address` are the two required LocalBusiness properties, that `telephone` should include the country code and area code, and that the markup feeds the business knowledge panel and the business carousel in Search and Maps.
- **Source**: https://schema.org/PostalAddress establishes the property set: `streetAddress`, `addressLocality`, `addressRegion`, `postalCode`, `addressCountry`, `postOfficeBoxNumber` and `extendedAddress`.
- **Source**: https://www.rfc-editor.org/rfc/rfc6068 defines the `mailto` URI scheme and the client behavior on activation (a message to the designated address that the user can edit, send or discard).
- **Source**: https://www.rfc-editor.org/rfc/rfc3966 defines the `tel` URI scheme, the global form with a leading "+" composed per E.164, the MUST on global form, the visual-separator rule, and gives `tel:+1-201-555-0123` as its example.
- **Source**: https://support.google.com/business/answer/3038177 (Guidelines for representing your business on Google) establishes the address, service-area, P.O. box, local phone number and no-redirect rules quoted above.
- **Source**: https://thetrustproject.org/ lists the eight Trust Indicators and describes Best Practices and Actionable Feedback as quoted above.
- **Source**: https://www.ftc.gov/business-guidance/resources/can-spam-act-compliance-guide-business establishes that a commercial email "must include your valid physical postal address" and lists the three acceptable forms.

## Related reading

- [E-E-A-T Is Content. Trust Signals Are Infrastructure.](/blog/blog-tool-trust-signal-surface-audit/)
- [NAP Consistency for Local Rank: Why "Street" vs "St." Costs You Map-Pack Position](/blog/blog-tool-nap-consistency/)
- [Every Place Your Business Needs a URL, and the One Line of Schema That Ties Them Together](/blog/business-listing-sameas-url-map/)
- [Your Google Maps Listing Decides The Phone Call. Audit It.](/blog/blog-tool-google-maps-audit/)
- [Pricing Pages and Careers Pages. The Two Transparency Signals Most Sites Hide](/blog/blog-transparency-page-trust/)

*This post is informational, not legal advice. Mentions of third parties are nominative fair use. No affiliation is implied.*


---

Canonical HTML: https://jwatte.com/blog/blog-mega-analyzer-visible-contact-signals/
RSS: https://jwatte.com/feed.xml
JSON Feed: https://jwatte.com/feed.json
Hero image: https://jwatte.com/images/blog-mega-analyzer-visible-contact-signals.webp
