Skip to content

enhance(mdim): set canonical url, include all views in sitemap, and include mdim title in page title#6607

Open
marcelgerber wants to merge 5 commits into
masterfrom
mdim-canonical-url
Open

enhance(mdim): set canonical url, include all views in sitemap, and include mdim title in page title#6607
marcelgerber wants to merge 5 commits into
masterfrom
mdim-canonical-url

Conversation

@marcelgerber

@marcelgerber marcelgerber commented Jun 11, 2026

Copy link
Copy Markdown
Member

We noticed that some Mdim views, like Number of newborns who have had a hepatitis B vaccine dose within the first 24 hours of delivery, are not findable on Google at all currently.

This PR makes three changes to Mdims, essentially:

  • Set <link rel="canonical"> in CF Functions, to ensure that the Mdim dimension choices are included in the canonical URL (so a ?metric=total would be part of the canonical URL, but a ?tab=map wouldn't)
  • Enumerate all of these views in the sitemap
  • Include the Mdim name in the page title, so we e.g. get Share of children vaccinated, by vaccine, World | Childhood vaccination coverage - by vaccine | Our World in Data

The sitemap change could have some negative SEO repercussions potentially, if Google finds that they don't like us indexing so many different views. But it's hard to know.

Antigravity says this:

Including hundreds of similar page variations in a sitemap wastes crawl budget and causes keyword cannibalization, diluting the domain's overall search authority. To mitigate this, ensure all variations have self-referential canonical tags and only list the default and select, high-value variations rather than every possible permutation.

Demo links:

@owidbot

owidbot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Quick links (staging server):

Site Dev Site Preview Admin Wizard Docs Docs Preview

Login: ssh owid@staging-site-mdim-canonical-url

Archive:

🎨 Bespoke dev server

SVG tester:

Number of differences (graphers): 0 ✅
Number of differences (grapher views): skipped
Number of differences (mdims): skipped
Number of differences (explorers): skipped
Number of differences (thumbnails): skipped

Edited: 2026-06-11 14:06:51 UTC
Execution time: 1.62 seconds

@marcelgerber marcelgerber marked this pull request as ready for review June 11, 2026 14:20
@marcelgerber marcelgerber requested review from ikesau and rakyi June 11, 2026 14:21

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d3c0d8da2e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +424 to +425
const value = searchParams.get(dim) ?? defaultChoice
newSearchParams.set(dim, value)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate mdim choices before canonicalizing

When a request includes a non-default or partial mdim query, this copies each incoming dimension value directly into the canonical URL and falls back to the global default for omitted dimensions. For sparse mdims, a URL like ?country=b can require a different default for a later dimension (or an incoming value can be invalid), while the client normalizes through filterToAvailableChoices; the canonical can therefore point at a view that is not actually rendered/available, creating duplicate or bogus canonical URLs for crawlers. Consider deriving the canonical dimensions from the same availability filtering used by the page, or only emitting combinations that exist in config.views.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's correct and unfortunate, but the only solution would be to include a comprehensive list of all available views and then filter them down.

I don't think we want to do that?

@rakyi rakyi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we wanted to treat a mutli-dim as the "page" and query params just as a way to interact with it and link to a specific view, similar to how search and latest work. Why do you think we need to change that? Is Ed aware of this proposed change?

Should we do the same for explorers?

@ikesau ikesau left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to me! Tested it locally on wrangler and it all works as expected.

I say it's worth a try, but I'm open to arguments otherwise.

Comment thread baker/sitemap.ts
loc: urljoin(BAKED_GRAPHER_URL, multiDim.slug),
lastmod: dayjs(multiDim.updatedAt).format("YYYY-MM-DD"),
}))
multiDims.flatMap((multiDim) => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just checked and it seems the max sitemap size is 50k

We're currently at ~6500

We currently have ~650 multidim views

We have ~6500 explorer views

So we should be okay with this approach without having to filter down the URLs by "high distinctiveness/value only"

baseUrl={baseUrl}
staticAssetMap={assetMaps?.static}
archiveContext={archiveContext}
attrs={{ "data-owid-mdim-dimensions": mdimDimensions }}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we maybe call this -inital-view-dimensions to be completely clear how it works?

@rakyi rakyi Jun 12, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, it would be better if we didn't nest it into an object. I know that we should not render this part on the client (for now), but always creating a new object with the same properties causes unnecessary re-renders and is a React antipattern.

baseUrl={baseUrl}
staticAssetMap={assetMaps?.static}
archiveContext={archiveContext}
attrs={{ "data-owid-mdim-dimensions": mdimDimensions }}

@rakyi rakyi Jun 12, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, it would be better if we didn't nest it into an object. I know that we should not render this part on the client (for now), but always creating a new object with the same properties causes unnecessary re-renders and is a React antipattern.

Comment thread site/Head.tsx
}
staticAssetMap?: AssetMap
archiveContext?: ArchiveContext
attrs?: Record<string, string | undefined>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A more idiomatic solution would be to extend the React.HTMLAttributes<HTMLHeadElement> type, and then we should be able to pass data- attribute as props to the <Head/> component.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A more complete example:

 interface HeadProps extends React.HTMLAttributes<HTMLHeadElement> {
    title?: string
  }

  export function Head({ title, children, ...rest }: HeadProps) {
    return (
      <head {...rest}>
        {title && <title>{title}</title>}
        <meta charSet="utf-8" />
        {children}
      </head>
    )
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants