Fixing og:url and Canonical Mismatches
The og:url tag names the permanent address of the thing being shared. When it is wrong, the damage is quiet but real: every product shows the home page card, shares of one article are split between five slightly different addresses, or a card links people to a staging site.
The fix is almost always to stop treating og:url as its own setting and print it from the same normalised address as the canonical tag. This guide shows the patterns that go wrong, how to spot each one, and how to generate a correct value on any platform.
What og:url actually does
In the Open Graph protocol, og:url is one of the four required properties, described
as the canonical URL of the object, the address that will be used as its permanent ID. Two things follow
from that description, and both explain why a wrong value causes trouble.
- It is an identity, not a label. Platforms that count shares, reactions or comments
against a link can attach them to the
og:urlvalue rather than to whatever address was pasted. If ten versions of a page all declare the sameog:url, their activity is pooled. If each declares itself, it is split. - It can redirect the scraper. Facebook in particular treats
og:urlas a pointer. When the value names a different address, its crawler fetches that address and builds the card from the tags it finds there. This is why anog:urlset to the home page on every page makes every shared link show the home page card.
The rel="canonical" link does the equivalent job for search engines. Google does not
document og:url as a canonical signal, so a mismatch will not directly change which page
Google indexes. The problem is that the two tags disagreeing means someone has made two decisions about
the page's main address, and at least one of them is wrong.
The patterns that go wrong
| What og:url says | What it should say | Usual cause |
|---|---|---|
https://www.example.co.uk/ on every page | Each page's own address | A hard-coded value in the layout, or a site-wide setting in a theme |
…/boots?utm_source=newsletter&utm_medium=email | …/boots | The template prints the request address instead of the canonical one |
http://example.co.uk/boots | https://www.example.co.uk/boots | A base URL setting left over from before HTTPS or a www change |
…/boots/ while canonical is …/boots | One form, used by both | Two different helper functions, one adding a slash |
/boots | https://www.example.co.uk/boots | A relative path from a routing helper |
https://staging.example.co.uk/boots | The live domain | An environment variable copied from staging to production |
…/boots?page=3 on a filtered or sorted listing | Depends on your canonical policy for that listing | Filters and sort order passed straight into the tag |
Why tracking parameters matter here
Links in emails, adverts and social posts pick up parameters such as utm_source, gclid
and fbclid. If the template echoes the request address into og:url, each campaign
produces a new identity for the same page. Platforms may then cache a separate card for each, and a later
fix to one does not fix the others.
Why the home page value is the worst case
Every other pattern splits or muddles a page's identity. The home page pattern replaces it. Sharing a product, a blog post or a job advert shows the home page title, description and image, and anyone reading the card has no idea what the link is about.
Checking what your pages declare
The OG / Twitter Tag Generator reports a missing or
invalid og:url. To see how it compares with the canonical, fetch the raw HTML and pull out
both values.
URL="https://www.example.co.uk/shop/walking-boots?utm_source=test&fbclid=abc123"
curl -sL "$URL" | grep -oiE '(property="og:url"|rel="canonical")[^>]*'
Deliberately add fake tracking parameters, as above. A correct page returns the clean address in both
tags, with none of the parameters. If either tag echoes utm_source or fbclid,
the template is using the request address.
Test several page types
Run the same check against the home page, a deep content page, a product with a variant selected, a paginated listing and a page reached with and without a trailing slash. Write down both values for each. Differences usually cluster by template, which points to the file to change.
Use a platform's view of it
Facebook's Sharing Debugger lists the canonical address it settled on and any redirect path it followed.
If it reports a different address from the one you entered, the page's og:url (or a redirect)
sent it there. That is a quick way to confirm the home page pattern without reading any markup.
Building one clean address
The reliable fix is to compute the page's address once, in one function, and print it into every tag that needs it. Deciding the rules takes five minutes; writing them down stops future drift.
- Scheme: always
https. - Host: one form, with or without
www, matching your redirects. - Path: the page's own path, lower-case if your server treats case as significant, with one trailing-slash convention used site-wide.
- Query string: removed by default. Keep only parameters that genuinely change the content and that you also keep in the canonical, such as a product variant if variants have their own pages.
- Fragment: always removed; nothing after a
#is sent to the server anyway.
A small example in PHP
<?php
function page_address(string $path): string {
$base = 'https://www.example.co.uk';
$path = '/' . trim(parse_url($path, PHP_URL_PATH) ?? '', '/');
return $path === '/' ? $base . '/' : $base . $path;
}
$address = page_address($_SERVER['REQUEST_URI']);
?>
<link rel="canonical" href="<?= htmlspecialchars($address) ?>">
<meta property="og:url" content="<?= htmlspecialchars($address) ?>">
The function throws away the query string and fragment, fixes the scheme and host, and removes trailing slashes except on the home page. The exact rules can differ on your site; what matters is that one function decides and both tags use it. In a CMS, the equivalent is a single field or setting that feeds both.
Host header. A misconfigured
proxy or a spoofed header can then put any domain into your canonical and og:url. Hard-code
the live host or read it from configuration.The fix, step by step
Step 1
Compare og:url with the canonical tag
Fetch the raw HTML of one page of each type, adding fake utm_source and fbclid
parameters to the address, and note the values of og:url and rel="canonical".
They should be identical and free of any parameters you added. Mark each template as correct, pointing
to the home page, echoing the request, using the wrong host or scheme, relative, or differing only by
a trailing slash.
Step 2
Find where og:url is printed
Search
the theme, layout files and plugin settings for og:url to find every place that prints it.
There should be exactly one. If an SEO plugin prints it and a theme or custom snippet prints another,
remove the extra one. If the value is typed into a site-wide settings box, that box is the cause of the
home page pattern and needs to be replaced with a per-page value.
Step 3
Build one normalised address
Write down the rules for the site's main address: https, one host form, one trailing-slash convention, no fragment and no query string except parameters that genuinely create different content. Put those rules in a single helper function, filter or template variable that takes the page's path and returns the full address, reading the host from configuration rather than from the incoming request so that no stray domain can leak in.
Step 4
Print both tags from that address
Replace
whatever currently feeds the canonical link and og:url with the single helper, so both tags
print exactly the same string on every page. Escape the value for use inside an attribute. If you also
print twitter:url or a URL in structured data, point those at the same helper, because a
third different address creates the same confusion in another place.
Step 5
Handle variants, languages and pagination
Decide deliberately for pages where the address is ambiguous. Product variants that
share one page should point to the main product address. Each language version with its own address should
declare itself, not the English page. Paginated listings should follow your canonical policy, normally
each page naming itself. Whatever you decide, the canonical and og:url must still agree
for each of these pages.
Step 6
Confirm the address resolves directly
Request
the og:url value itself with curl and check it returns status 200 with no redirect. A value
that redirects, returns 404 or lands on a login page gives platforms a broken identity. Then rerun the
comparison from step one, run a few pages through the generator, and use the Sharing Debugger on a previously
affected page to fetch a fresh card.
Platform notes
WordPress
Yoast SEO and Rank Math both derive og:url from the canonical address they calculate,
so if you set a custom canonical on a post, the share address follows it. A mismatch on a WordPress site
usually means a second source: a theme with its own Open Graph output, a social sharing plugin, or code
in functions.php that hard-codes a value. Turn the extra source off rather than trying to
make two outputs agree. Plugin settings are covered in Open
Graph in WordPress.
Shopify
Liquid provides a canonical_url object that already strips most parameters. Themes that
use {{ canonical_url }} in both the canonical link and og:url are consistent
by default. Problems appear when a customised snippet uses {{ request.path }} or builds
the address from shop.url and a handle, which can produce a different form for collection-scoped
product addresses.
Next.js and similar frameworks
In the App Router Metadata API, set metadataBase once in the root layout, then give each
route alternates.canonical and openGraph.url from the same relative path. Relative
values are resolved against metadataBase, so both become full addresses from one setting.
export async function generateMetadata({ params }) {
const path = `/shop/${params.slug}`;
return {
alternates: { canonical: path },
openGraph: { url: path, type: 'website' },
};
}
Static site generators
Hugo's .Permalink, Eleventy's page.url combined with a site base, and Jekyll's
page.url | absolute_url all give a stable address from configuration. Use the same expression
in both tags and set the production base URL in the build configuration rather than in individual templates.
Harder cases
- Syndicated or duplicated content. If an article also appears on a partner's site
with a canonical back to yours, their
og:urlmay also name your address. That pools shares on your page, which is usually what both sides want, but agree it in writing. - Campaign landing pages that should stay separate. If a landing page deliberately
differs from the main page, give it its own address in both tags. Do not point its
og:urlat the main page while showing different content, because the card and the page will not match. - Moved pages. After a URL change, update the tags on the new page to name the new
address. The old address should redirect; do not leave an
og:urlon the new page that still names the old one to keep share counts, because the old address no longer serves the page directly. - Encoded characters. Paths with spaces or non-ASCII letters should be percent-encoded
consistently.
caf%C3%A9andcafécan be treated as different addresses by some readers. - Language subfolders. A French page at
/fr/should name itself in both tags. The connection to the English version belongs inhreflangandog:locale:alternate, covered in fixing og:locale issues.
Keeping it consistent
- One helper, used everywhere. Any new template that needs an address should call the same function. Code review should reject a template that assembles its own.
- An automated check. A test that fetches a few addresses with fake tracking parameters
and fails when
og:urldiffers from the canonical, or contains a parameter, catches regressions immediately. - Environment-specific configuration. Keep the base URL in environment configuration and check it is the live domain on production after every deployment.
- Treat address changes as migrations. Changing trailing-slash policy or the www host
changes every
og:urlat once. Plan redirects and expect platforms to build new cards.
For how the canonical tag itself should be set, see fixing canonical tags, and for www and non-www consistency, fixing www canonicalisation.
1. Should og:url always be the same as the canonical URL?
In almost every case, yes. Both tags answer the same question, which address is the main one for this content, and one for search engines and one for sharing platforms. If they disagree, one of them is wrong. The rare exception is a deliberate arrangement such as syndicated content, and even then both tags should normally name the same original address. Generating both from one variable in your template is the simplest way to keep them identical.
2. Why does every page on my site share with the home page preview?
Almost certainly because og:url on every page is set to the home page address. Facebook and some other readers treat og:url as the true address of the content, fetch that address, and build the card from the home page tags. The usual source is a theme or settings box where someone typed the site address once. Replace it with a value calculated per page, then refresh the cached cards for affected pages.
3. Should og:url include UTM or other tracking parameters?
No. Tracking parameters describe how a visitor arrived, not what the page is. Including them gives each campaign its own identity, splits share and reaction counts, and can create separate cached cards that do not update when you fix the original. The shared link itself can carry parameters so your analytics still work; the og:url inside the page should name the clean address without them, exactly as the canonical tag does.
4. Can og:url be a relative path like /about?
It should not be. The Open Graph protocol expects a full URL, and readers that receive a relative path may ignore it, resolve it incorrectly or report an error. Always print the scheme and host, as in https://www.example.co.uk/about. Many frameworks and plugins resolve relative paths for you when a base address is configured, so check the served HTML rather than the template to be sure what readers actually receive when they fetch the page.
5. Does a wrong og:url affect my Google rankings?
Not directly. Google relies on the rel canonical link, redirects, sitemaps and internal links to choose a canonical address, and it does not document og:url as one of its signals. The effect of a wrong og:url is on sharing: wrong cards, split counts and stale previews. A mismatch is still worth fixing, because it often reveals that the canonical tag is being generated by a different piece of code that may be wrong too.
6. What should og:url be for product variants?
It depends on whether the variants have their own pages. If a colour or size is chosen on one product page, and the canonical points to the main product address, og:url should do the same, so all shares count towards one product. If each variant is a separate page with its own canonical, og:url should name that variant. The rule is the same as always: match whatever the canonical says for that page.
7. Do I need both og:url and twitter:url?
No. X does not require twitter:url and reads the shared address and Open Graph tags when building a card. Adding twitter:url gives you nothing extra, and it gives you one more value that can disagree with the others. If a plugin prints it, make sure it uses the same address helper as og:url and the canonical, or switch it off. The same caution applies to any URL written into structured data.
The OG / Twitter Tag Generator builds the Open Graph and X card block for your page, validates it against the requirements of Facebook, LinkedIn and X, predicts how the preview will render and flags every tag that is missing or invalid.
Open Open Graph Fixes →