The question to settle before touching any setting is who owns the canonical on your site. On a hosted builder the platform usually does. On a self-hosted CMS it may be core, a plugin or the theme, and duplicate tags appear when more than one of them decides it is responsible. In a framework it is your own code. The groups below follow that division and use each platform's default behavior, not what it can be configured to do.
Writes a canonical automatically
Yoast SEO adds a self-referencing tag to essentially every indexable page type on a WordPress site, archives included, and removes the core tag so each page ends up with exactly one. The per-page override sits in the Advanced section. Its most common failure is stale data rather than tag logic: canonicals that still name a staging domain after a migration, because the stored URLs traveled with the database. Rank Math takes the same approach, with an override field under its own Advanced tab and a filter, rank_math/frontend/canonical, for programmatic control.
All in One SEO (AIOSEO) supplements core in a similar way and has its own per-page override field and a filter for developers. Whichever plugin you choose, run only one. Two SEO plugins, or one plugin plus a theme that hardcodes its own tag in the header template, is the standard route to a page that prints two canonicals, and a page with two conflicting canonicals gives Google a reason to disregard both of them.
Shopify generates canonicals on products, collections, pages and articles, and strips the collection segment so that a product reached through a collection still canonicalizes to its /products/ URL. The weak points are internal links that use the longer collection path and apps or theme edits that add a second tag, not the platform logic itself. BigCommerce likewise folds a product's several category URLs into one canonical product URL, but offers no free-text override; the canonical simply follows the product's Custom URL.
Wix sets a self-referencing default on every page and lets you replace it, with one side effect worth knowing before you do: a custom value can drop that URL from the Wix sitemap. The fix is to revert to the default rather than to add the page back by hand. Ghost writes the tag through its {{ghost_head}} helper, so any theme that keeps the helper keeps the tag, and each post has a Canonical URL field suited to content that first appeared elsewhere.
HubSpot generates self-referencing canonicals on pages and blog posts, with an override in each page's advanced options and host and protocol handled through the primary domain. Blog listing pages are the documented exception and get no canonical by default, which explains many audit warnings on HubSpot blogs. Framer adds one automatically on connected domains and has a site-level field for reverse-proxy setups, but no per-page override.
Automatic, but check the output
WordPress core emits a canonical only on singular content: posts, pages, attachments and custom post types. The front page, the blog index, category and tag archives, and author and date archives get none, which is the gap an SEO plugin exists to close. Core also runs redirect_canonical(), a separate system that redirects untidy URLs and is often confused with the tag. WooCommerce adds no canonical layer of its own. It inherits core and the plugin, and its real work is the filter and sort URLs a shop generates.
Drupal core adds self-referencing tags on entity pages in versions 8, 9 and 10, and the Metatag module controls and overrides them. Check Views pages and the Metatag output after any module change, since a doubled canonical is a known failure on the platform. Squarespace manages a self-referencing tag you cannot natively edit, and its Code Injection feature adds a tag rather than replacing the existing one, so a hand-added canonical produces two on the same page.
Blogger writes the tag through the all-head-content include on standard themes and strips the ?m=1 mobile parameter from it, but custom themes that print a second tag, or hand-coded tags that carry parameters, break it. On a custom theme, View Source is the only reliable way to see which of those applies. Nuxt sits between two groups. Core writes nothing, while the Nuxt SEO modules generate a canonical from the site URL and the current route, so their defaults are what to audit: trailing slashes, a query whitelist that keeps sort and filter values, and any route running in SPA mode, where the tag exists only after JavaScript runs.
Manual: nothing until you set it
Webflow is the exception among site builders. It emits no canonical until you enter a global canonical URL in the SEO tab of the site settings, and CMS collection items cannot take a per-page override, which matters for syndicated content that needs to point at an original. Magento, now Adobe Commerce, ships with product and category canonicals switched off; they are enabled in the catalog Search Engine Optimization settings, and even then they do not strip layered-navigation parameters from the canonical.
Joomla is weak by design. SEF and non-SEF index.php URLs serve the same content, core does not reliably point one version at the other, and a dedicated canonical extension is the practical fix. The code frameworks go further and put the whole job on the developer. Next.js is opt-in per route, through alternates.canonical in the App Router Metadata API, and depends on metadataBase being set so relative values resolve to the production host rather than a preview or local address.
React writes no canonical of its own. react-helmet-async is the usual tool, and a tag added only in the browser is absent from the initial HTML that other crawlers and server-side checks read. Server-side rendering or prerendering puts the tag where it belongs, in the HTML the server sends. PHP outputs nothing unless you print it, and Laravel emits none in core either. The naive version builds the URL from the incoming Host header, which the client controls, so a forged request can produce a canonical naming someone else's domain that a cache then serves to everyone. Build the origin from configuration and leave the raw query string out.
Checks that apply everywhere
Whatever the group, verification is the same. Open the raw source and count the canonical tags; there should be exactly one. Confirm the URL is absolute and matches the protocol, host and trailing slash actually served. Confirm the target returns a 200 and is indexable. Then repeat after every theme update, plugin install or migration, because on most platforms the canonical breaks through a change made somewhere else rather than through its own settings.