How to write anchor text: the href, the words, and the two fallbacks

How to write anchor text Google can actually use: a real href on an <a> element, a description of the destination between the tags, and — when the text is missing — the only two fallbacks Google's documentation names.

Crawling & Indexing7 min read2392 views
How to write anchor text: the href, the words, and the two fallbacks

To write anchor text that Google can use, put a description of the destination between the tags, and make sure the element around it is an <a> with a real href. Those are two separate requirements and they fail separately: a link with perfect wording and no href is not a link, and a followable link with no text tells Google nothing about where it goes.

Before you start

This chapter assumes you already decided which pages should link to which — that is a site structure question, and it is covered in internal linking strategy. Here we are one level down, at the element itself: the href, the words, and the two fallbacks Google names when the words are missing.

What Google actually reads in a link

Three things, in a fixed order of preference. Make your links crawlable, retrieved 2026-08-28, opens with the element rule: "Generally, Google can only crawl your link if it's an <a> HTML element (also known as anchor element) with an href attribute." It then names the anchor text, and then two fallbacks for when the anchor is empty: the title attribute, and, for a link wrapped around an image, that image's alt.

LayerWhat it must beIf it is missing
Element<a> with an hrefNot crawled as a link
href valueAn address, not javascript:…Google "may still attempt" to resolve it
TextWords between the tagsFalls back to title
Image linkalt on the inner imageNothing left to read

The order matters when you are fixing things in bulk. An icon link with an aria-label and no alt reads fine to a screen reader and has no documented name for search — aria-label does not appear anywhere on that page. Adding alt to the image inside it fixes the search side without changing a pixel.

An href decides whether the link exists. The text decides what it is worth.

How to write anchor text that survives being read alone

Google publishes the test, and it takes about two seconds per link: "Try reading only the anchor text (out of context) and check if it's specific enough to make sense by itself. If you don't know what the page could be about, you need more descriptive anchor text."

Run your own links through it before you argue about keywords. "See more" fails. "Read the story" fails. "GPTBot user agent list" passes, and so does "our 2026 refund policy". The same page warns off both directions of the failure — text that is too generic, and text that is "weirdly long", where the whole sentence has been swallowed by the link.

Do it: six steps on one page

Work through one page at a time, in this order. Steps one to three remove links that give a crawler nothing; steps four to six improve the ones that already work.

  1. List every anchor on the page and flag two conditions: no href attribute, and no text after whitespace is collapsed. Use the script below, or your browser console.
  2. For every flagged anchor that wraps an image, write an alt that describes the destination, not the picture. A thumbnail link to an article should carry the headline.
  3. For every flagged anchor that is a control — a menu opener, a vote button, a carousel arrow — leave it alone and confirm the destination it hides is reachable through a normal link elsewhere on the site.
  4. For anchors that have text, apply the out-of-context test. Rewrite the failures to name the destination in three to six words.
  5. Cut any anchor text over roughly 100 characters down to the part that names the thing. The surrounding sentence keeps the rest, and Google's page explicitly asks you to leave context outside the link.
  6. Check that you have not repeated the same anchor text for two different destinations, or two different anchor texts for one destination. One destination, one phrase, used consistently.

Step six is the one people skip, and it is the one that compounds. If three pages link to your pricing page as "pricing", "plans" and "see costs", each phrase carries a third of the description, and an answer engine trying to work out what that page is has three partial names for it instead of one. Pick the phrase a reader would search for, then use it every time. Variation in link text is not a style choice; it is a way of spending the same signal three times.

Deliverable: the audit script and the checklist

This prints every anchor on a live page that gives a crawler nothing — no href, or no text and no image alt. It needs nothing but Python 3.

import sys, urllib.request
from html.parser import HTMLParser

class Links(HTMLParser):
    def __init__(self):
        super().__init__(convert_charrefs=True)
        self.rows, self.cur = [], None
    def handle_starttag(self, tag, attrs):
        a = dict(attrs)
        if tag == "a":
            self.cur = {"href": a.get("href"), "text": "",
                        "aria": (a.get("aria-label") or "").strip(),
                        "img": (a.get("title") or "").strip()}
        elif tag == "img" and self.cur is not None:
            self.cur["img"] = (a.get("alt") or "").strip()
    def handle_data(self, d):
        if self.cur is not None:
            self.cur["text"] += d
    def handle_endtag(self, tag):
        if tag == "a" and self.cur is not None:
            self.rows.append(self.cur)
            self.cur = None

req = urllib.request.Request(sys.argv[1], headers={"User-Agent": "Mozilla/5.0"})
page = urllib.request.urlopen(req, timeout=30).read().decode("utf-8", "replace")
p = Links()
p.feed(page)
bad = 0
for r in p.rows:
    named = r["text"].strip() or r["img"]
    if r["href"] is None or not named:
        bad += 1
        why = "no href" if r["href"] is None else "no text"
        print(f'{why:8} {(r["text"].strip() or r["aria"] or "")[:40]:40} {(r["href"] or "")[:50]}')
print(f'{bad} of {len(p.rows)} anchors give a crawler nothing')

Save it as linkcheck.py and run python3 linkcheck.py https://your-site.example/. It reads the delivered HTML only, which is the point: it sees what a crawler sees before any script runs.

CheckPass condition
ElementEvery navigation target is an <a href>
Empty textZero, or each one has an image alt
Out-of-contextAnchor text names the destination alone
LengthRoughly 3–8 words, not the whole sentence
ConsistencyOne destination, one phrase
CrowdingNo two links touching with no words between

Three ways this goes wrong

All three show up on real production sites, and none of them looks broken in a browser.

  1. A dropdown opener is not a link, and it was never meant to be one. Menu triggers often have no href by design. That is fine for the trigger and fatal for the pages behind it if they appear nowhere else. Check the footer and the sitemap before you change the menu.
  2. An icon link carrying only an aria-label passes an accessibility audit and leaves search with nothing, because the documented fallbacks are title and image alt. Keep the aria-label; add the alt.
  3. Anchor text over 100 characters usually means a whole headline or paragraph got wrapped. Google's page asks you to keep context around the link, not inside it — chaining several links together with no words between them costs you that context for every one of them.

Where this stops

Anchor text will not rescue a page that a crawler cannot reach, and it cannot tell you how much any single link is worth. Google's documentation describes what it reads; it does not publish a weight, and no honest checklist can supply one. If pages are missing from the index, start one layer up with the AI crawler accessibility check — reachability first, wording second. This chapter also assumes ordinary editorial links; paid and user-generated ones need rel qualification, which is a different rule from a different page.

Common questions

How many words should anchor text be?

Google gives no number, only two directions to avoid: too generic and "weirdly long". Three to six words names most destinations, and the out-of-context test settles the rest.

Should I put my target keyword in every internal link?

No. The same page calls keyword stuffing a spam policy violation and asks whether "the reader need these keywords to understand the next page". Consistency beats repetition: one phrase per destination, used where it fits the sentence.

Is aria-label enough for a link with an icon?

For screen readers, yes. For search, it is not named in Google's documentation on link text, and the two documented fallbacks are title and the inner image's alt. On 27 homepages measured in descriptive link text, aria-label alone was the single most common way a text-less link was named.

Do links added by JavaScript count?

Google's page says they are crawlable "as long as it uses the HTML markup shown above" — that is, they end up as <a href>. The script above will not see them, so verify those with the URL Inspection tool's rendered HTML instead.

Are javascript: links still a real problem?

They are listed as not recommended, and they have become rare in practice: across 5,272 anchors in this crawlable links survey, zero used one. Spend the time on empty link text instead.

Part of the QueryWin handbook · Level 2

How to write anchor text: the href, the words, and the two fallbacks