Web & SEO

Technical SEO Checklist for Developer Portfolio Websites

Most developer portfolios are invisible to Google — not because the code is bad, but because nothing on the page tells a crawler who you are. Here is the ordered checklist I used on my own site, with the reasoning behind each step.

A portfolio has an unusual SEO goal. You are not trying to rank for a competitive commercial term — you are trying to become the canonical entity for your own name, and then earn a bit of long-tail traffic from the things you build. Those two goals need different work, and the entity work comes first.

1. Pick one host and mean it

Before anything else: decide whether your site lives at example.com or www.example.com, and make the other one 301-redirect to it. Serving identical content on both is the most common self-inflicted wound in this whole list. Google treats them as separate sites, splits whatever authority you have between them, and picks a canonical for you — often not the one you wanted.

Then check the obvious variants actually resolve to a single URL:

  • http://https://
  • www → apex (or the reverse — just be consistent)
  • /index.html/
  • Trailing slash handled consistently

Every page then needs a self-referencing canonical tag pointing at that one chosen form:

<link rel="canonical" href="https://example.com/">

Check this first. A canonical tag pointing at a hostname that redirects — or worse, does not resolve — will quietly suppress indexing of the whole site, and nothing else you do will compensate.

2. Titles and descriptions that name the person

Your homepage title is the strongest single signal for your own name. It should contain the name you want to rank for, the role, and the word "portfolio" — in under about 60 characters so it does not truncate:

<title>Jane Doe — Full Stack &amp; Cloud Developer Portfolio</title>

If you go by more than one form of your name — a short form, an initial, a legal name — use one in the title and make sure the other appears naturally in the visible body copy. Do not stuff both into the title.

The meta description does not affect rankings, but it does affect click-through, and click-through on a name query is a meaningful quality signal. Write it as a sentence a human would read, around 150–160 characters, including the name and what you actually do.

Every page needs its own. Duplicate titles across a portfolio and its project pages are a real and very common problem — Portfolio repeated eight times tells Google the pages are interchangeable.

3. Person schema — the piece almost everyone skips

This is where a portfolio wins or loses. Structured data is how you state, in a machine-readable form, that this website is about a specific human being. Without it, Google has to infer your identity from unstructured text. With it, you are handing over a labelled record.

{
  "@context": "https://schema.org",
  "@type": "Person",
  "@id": "https://example.com/#jane",
  "name": "Jane Doe",
  "alternateName": ["J. Doe", "Jane"],
  "url": "https://example.com/",
  "image": "https://example.com/image/jane-doe.jpg",
  "jobTitle": ["Full Stack Developer", "Cloud Engineer"],
  "description": "Jane Doe is a full stack developer specialising in ...",
  "knowsAbout": ["React", "Node.js", "AWS", "PostgreSQL"],
  "alumniOf": { "@type": "CollegeOrUniversity", "name": "..." },
  "sameAs": [
    "https://github.com/janedoe",
    "https://www.linkedin.com/in/janedoe"
  ]
}

A few things that make a real difference:

  • Use a stable @id. A URI like https://example.com/#jane lets every other node on every other page reference the same person. Your project pages, your articles and your blog should all point their author at that one @id. That is how authority accumulates onto a single entity rather than scattering.
  • alternateName handles name variants — the short form, the initial form, the spelling people actually type.
  • knowsAbout is your topic map. It is how you associate yourself with technologies, which is what drives "[technology] developer [name]" style queries.
  • Wrap everything in an @graph with WebSite, ProfilePage and BreadcrumbList nodes cross-referencing by @id. One script tag, one connected graph, no contradictions.

Validate with the Schema Markup Validator and Google's Rich Results Test before you ship. Malformed JSON-LD is silently ignored, so a typo costs you the entire benefit with no warning.

4. sameAs: binding your GitHub and LinkedIn to your site

The sameAs array is a claim: "these profiles are me." It is one of the clearest inputs to entity resolution — how a search engine decides that the GitHub account, the LinkedIn profile and this website are one person rather than three.

But a one-way claim is weak, because anyone can list anyone. Make it reciprocal:

  • Put your site URL in your GitHub profile website field, and in your profile README.
  • Put it in your LinkedIn contact info and the Featured section.
  • Use the same display name and the same profile photo everywhere. Consistency across profiles is itself a corroborating signal.

Then reinforce it in HTML with rel="me" on the outbound links:

<a href="https://github.com/janedoe" rel="me noopener" target="_blank">GitHub</a>

Now the claim is bidirectional and machine-readable from both ends. This is the highest-leverage hour of work in the entire checklist, and it costs nothing.

5. Headings, landmarks and crawlable content

The mechanical stuff, which is easy to get right and easy to get wrong:

  • Exactly one <h1> per page, and no skipped levels — h2 should not be followed by h4. Screen readers and crawlers both build an outline from this.
  • Real landmarks: <header>, <nav>, <main>, <footer>. A page built entirely from <div> gives a crawler no structural hints at all.
  • Descriptive link text. Eight links that all say "GitHub" tell Google nothing and fail WCAG 2.4.4. "Source on GitHub — HydroSmart" is better for both.
  • Descriptive alt text and filenames. hydrosmart-esp32-hardware.jpg beats 7.jpg. Image filenames are a genuine, if minor, ranking input for image search.
  • Kill dead links. href="#" placeholders on "View demo" buttons waste crawl budget and look broken. Remove the link or point it somewhere real.

If your content is revealed by JavaScript — scroll animations that start at opacity: 0 are the usual culprit — add a <noscript> fallback that makes it visible. Google does render JavaScript, but rendering is queued and not guaranteed. Do not bet your only copy of the content on it.

6. Core Web Vitals for a portfolio

Portfolios have a characteristic performance profile: a large hero image and a lot of decorative animation. Both are fixable without touching the design.

  • LCP is almost always the hero image. Preload it, set fetchpriority="high", and never put loading="lazy" on it — lazy-loading your LCP element is a self-inflicted delay.
  • CLS comes from two places: images without width/height attributes, and webfonts swapping in at a different metric. Set explicit dimensions on every image, and define a fallback @font-face with size-adjust so the swap does not reflow text.
  • INP is where animated portfolios lose. Canvas effects running an unbounded requestAnimationFrame loop hold the main thread for the entire session. Start them on requestIdleCallback, pause them on visibilitychange, and skip them entirely under prefers-reduced-motion.
  • Third-party scripts — form SDKs, analytics, chat widgets — should load on interaction, not on page load. A contact-form SDK that only matters once someone focuses the form has no business blocking first paint.

Scroll handlers deserve a specific mention. Reading offsetTop inside a scroll listener forces synchronous layout on every event. Measure once, cache the values, re-measure on resize, and batch the work in a single requestAnimationFrame.

7. robots.txt, sitemaps and Search Console

The plumbing. It is quick, and skipping it means Google finds your site whenever it happens to.

  1. robots.txt at the root, allowing crawl and naming your sitemap with an absolute URL.
  2. sitemap.xml listing every indexable URL — and only indexable ones. Do not list pages that redirect, 404 or are canonicalised elsewhere; a sitemap full of noise reduces trust in the whole file.
  3. Google Search Console. Verify the property (domain verification via DNS covers every subdomain and protocol at once), submit the sitemap, then use URL Inspection → Request Indexing on your homepage.
  4. Bing Webmaster Tools. Add the site and use "Import from Google Search Console" — it is genuinely one click, and Bing data also feeds several AI answer engines.

Then watch the Pages report rather than obsessing over rank. "Discovered – currently not indexed" on a small site usually means thin content or weak internal linking, not a penalty.

8. The off-site half nobody wants to do

Everything above makes you eligible to rank for your name. What actually gets you there on a competitive name is corroboration from places Google already trusts:

  • GitHub profile website field and profile README (a real, crawlable, high-authority link)
  • LinkedIn contact info and Featured section
  • Dev.to, Hashnode or Medium — cross-post an article with a rel="canonical" pointing back at your own copy, so you get the reference without competing with yourself
  • Stack Overflow, CodePen, Frontend Mentor, HackerRank, LeetCode profiles — each one is another corroborating record of the same identity
  • Any university department, club or hackathon page that will list you — .edu-adjacent links are disproportionately trusted

The pattern that matters is consistency: same name, same photo, same site URL, everywhere. You are not link-building so much as making the same claim in enough independent places that it becomes a fact.

9. The order that matters

If you only do part of this, do it in this order. Each step is worth more than everything below it:

  1. Fix host canonicalisation and canonical tags — everything else depends on it.
  2. Add Person schema with sameAs, and make the profile links reciprocal.
  3. Write a homepage title and description that name you.
  4. Submit to Search Console and request indexing.
  5. Fix LCP and CLS.
  6. Add real content — project write-ups and articles that give you something to rank for beyond your own name.

And then wait. Entity consolidation is not instant; Google needs to re-crawl, render, and see the corroborating signals line up. Expect movement on your own name in weeks, and on broader terms in months. The work compounds, but only if you got step one right.