Query Parameters and SEO in Vue
- Query parameters can change page content or create duplicate URLs. Choose rules from what each parameter does
- Keep meaningful parameters in a canonical URL. Remove tracking-only parameters when they do not change content
- Pagination and useful filtered pages can need distinct canonical URLs. A path segment is a design choice, not an indexing requirement
- Validate values in the data-serving application. A canonical URL does not reject invalid requests
For path and query design, see URL Structure.
Vue Router exposes query values through useRoute().query. Values can be strings, null, or arrays. Repeated parameters and client navigation need explicit handling.
Sorting, filters, tracking, and pagination have different effects. Many combinations can increase crawling of duplicate or similar pages, but a filtered result or later page may contain distinct content.
Quick Setup
Start with an installed Vue Router app and install the Unhead plugin. These are a utility and component-setup excerpt, not a router or server installation.
This example keeps functional parameters and removes keys the example app treats as tracking-only. It normalizes bare query values to empty strings; use it only if those mean the same thing in your app. Change the tracking list if a listed key changes content.
import type { LocationQuery } from 'vue-router'
export function canonicalUrl(path: string, query: LocationQuery, origin: string) {
const url = new URL(path, origin)
for (const [key, raw] of Object.entries(query)) {
// These keys are tracking-only in this example app.
if (key.startsWith('utm_') || ['fbclid', 'gclid'].includes(key))
continue
for (const value of Array.isArray(raw) ? raw : [raw]) {
url.searchParams.append(key, value ?? '')
}
}
url.searchParams.sort()
return url.href
}<script setup lang="ts">
import { useHead } from '@unhead/vue'
import { useRoute } from 'vue-router'
import { canonicalUrl } from '../utils/canonical-query'
const route = useRoute()
useHead({
link: [{
rel: 'canonical',
href: () => canonicalUrl(route.path, route.query, 'https://mysite.com')
}]
})
</script>The getter reads current route values after navigation. Repeated values remain repeated parameters. Sorting parameter names stabilizes their order without sorting repeated values.
This self-canonical policy assumes the retained parameters describe the intended page. Choose a different canonical only for duplicate or similar content. For initial HTML output, use an SSR or generation pipeline that serializes the head.
Common Parameter Types
| Parameter type | Example | Decision |
|---|---|---|
| Filters | ?color=red | Distinct useful result, duplicate variant, or intentionally excluded view? |
| Sorting | ?sort=price | Does it only reorder the same content, or change the items on this page? |
| Pagination | ?page=2 | Give each valid page its own URL and canonical |
| Tracking | ?utm_source=mail | Omit from canonicals if it does not change content |
| Search | ?q=shoes | Choose a deliberate indexing and crawling policy |
| Sessions | ?sessionid=abc | Avoid generating crawlable session-specific public URLs |
Filter Parameters
Filters can produce many URL combinations. Some have useful distinct content. Others repeat a category or return no results. Google's faceted-navigation guidance distinguishes facets you want crawled from those you do not.
Block Filtered Pages
If a view should be excluded from Search, use noindex on a crawlable response. Do not add it to all filters automatically. To consolidate duplicates, prefer a canonical to genuinely similar content. A crawl restriction in robots.txt serves a different purpose and prevents Google from reading a page's noindex or canonical.
Move Important Filters to Path
A category can use /products/shoes or /products?category=shoes. Choose a stable, understandable pattern and link consistently. A path does not make thin content valuable, and a query does not prevent indexing.
Sort Parameters
Sorting may reorder the same items. Combined with pagination, it can also change which items appear on a page. Compare the actual output before consolidating URLs.
Include Sort in Canonical
The Quick Setup preserves sort values. Use that policy when the sort URL should remain distinct. Allow only supported sort values in your data loader or server, and reject invalid requests deliberately. Client-side canonical generation is not server validation.
Block Sort from Indexing
Use noindex only when the view should be excluded from Search. For duplicate ordering variants you want consolidated, a canonical can be the better policy. Avoid contradictory noindex and canonical instructions.
Pagination Parameters
Google recommends a unique URL and self-referencing canonical for each page. Do not canonicalize every page to page one. The Quick Setup retains page values; see the Pagination SEO guide.
Validate page syntax and the real range in your data-serving layer. Return an appropriate missing-page response for nonexistent pages rather than silently presenting page one at an invalid URL.
Tracking Parameters
Tracking-only values can produce multiple URLs for the same content. They can be omitted from canonical URLs while remaining in the browser URL for analytics.
Strip Tracking Params
The Quick Setup removes utm_*, fbclid, and gclid under an explicit tracking-only assumption. It preserves other values, including repeated filters. Names such as ref and source can have application meanings; do not remove them blindly.
Server-Side Parameter Handling
A tracking parameter does not require a redirect. Redirecting before analytics reads it can lose attribution. If you intentionally redirect, preserve meaningful query values and verify both the HTTP Location and your attribution behavior. Use your server's documented URL APIs; a Vue Router guard cannot set an HTTP status.
Parameter Order Consistency
The utility sorts parameter names before serialization. Use the same convention in generated links. Repeated value order remains unchanged because your application may use that order.
When updating queries through Vue Router, call router.push() or router.replace(). navigateTo() is a Nuxt composable, not a Vue Router API. See programmatic navigation.
Search Parameters
Choose a policy for internal search URLs based on the content and intended audience. Result count alone does not establish quality.
Block Thin Search Results
If internal search pages should not appear in Search, serve noindex on those pages and allow crawling until Google can read it. Do not use an arbitrary five-result threshold as a general quality rule.
robots.txt for Search
For a crawl policy that excludes the entire app-owned /search path:
User-agent: *
Disallow: /searchThis also matches paths starting with /search; choose a narrower rule if needed. It prevents crawling, not guaranteed URL exclusion from Search. Do not combine it with a page directive you expect Google to fetch.
Testing Parameter Handling
Compare user-declared and Google-selected canonicals in Search Console's indexed URL information. A live fetch shows current response behavior; it does not predict Google's next canonical selection.
Manual Verification
curl 'https://mysite.com/products?sort=price'Inspect the response head. A client-only setup may add the canonical after JavaScript runs; inspect rendered DOM separately. A raw response cannot prove that client operation occurred.
Test Parameter Variations
For the Quick Setup's self-canonical policy:
| URL | Canonical |
|---|---|
/products | https://mysite.com/products |
/products?sort=price | https://mysite.com/products?sort=price |
/products?color=red&color=blue | Both color values retained |
/products?utm_source=mail | https://mysite.com/products |
/products?page=2 | https://mysite.com/products?page=2 |
Also test client transitions between these URLs. Existing head tags must update with the route.
robots.txt Parameter Blocking
Google's faceted-navigation guidance supports crawling restrictions for facets you do not want crawled. Apply them to deliberately excluded application parameters, not all tracking or pagination URLs.
Do not use robots.txt for canonicalization. Blocked pages cannot expose their canonical or noindex to the crawler. Search Console's URL Parameters tool was retired in 2022; page directives and crawl rules remain different controls.
Common Mistakes
Static snapshots: destructuring route.query or reading a computed value once can leave tags stale after navigation. Read reactive values in a getter.
Discarding meaningful values: later pages and useful filters are not automatically duplicates. Preserve the content's identity.
Conflicting controls: a robots.txt block prevents fetching page-level canonical and noindex instructions.
Treating a canonical as validation: validate requests in the data-serving layer. A head tag does not reject unsupported values.
Nuxt SEO Utils supplies canonical handling with configurable query retention. Configure that policy for your content rather than assuming every query is disposable.
Checklist
- Classify parameters by actual content, tracking, pagination, and crawl behavior
- Keep valid pagination and useful distinct filter identities
- Remove only tracking values that do not change content
- Update canonical output after Vue Router navigation, including repeated query values
- Validate values in the data-serving layer and inspect HTTP and rendered output separately
Pre-launch setup, post-launch verification, and ongoing monitoring. Interactive checklist with links to every guide.