On-page and technical SEO for a cannabis website means making sure Google can reach every page that matters, read the content in the HTML, and understand what each page is for. On most dispensary and brand sites the biggest losses come from four places: a menu embed that hides products from crawlers, an age gate that blocks the page behind it, filter URLs that waste crawl time, and templated pages that say nothing unique. Fix access and rendering first, then titles, headings, schema and content.
What on-page and technical SEO covers
On-page and technical SEO for a cannabis site is the work that decides whether your pages can rank at all, before links or content volume come into play. Technical SEO covers access: can Googlebot fetch the page, render it, and add it to the index. On-page SEO covers meaning: does the title, heading, copy and markup tell Google and the shopper what the page is for. Both halves fail in predictable ways on cannabis sites, because the industry runs on the same few menu providers, age gates and CMS themes.
Order matters more than the checklist. A perfect title on a page Google never indexed does nothing, so work in the order a crawler meets your site: access (robots.txt, firewall, age gate), rendering, indexing, and only then the on-page layer. Start with a crawl. Screaming Frog's free version covers 500 URLs and returns every title, heading, status code and click depth in one spreadsheet. Then pair it with a Search Console domain property, verified by a DNS TXT record you never delete, so every host and protocol reports in one view. Performance, Pages and URL Inspection carry most of the routine work.
Title tags and meta descriptions
Title tags are the cheapest on-page fix on most cannabis sites, because templates fill them in badly. Sort a crawl export by title and look for repeats. A common pattern: a three-store shop with "Dispensary | Shop Cannabis Online" on 41 pages because the template used a default whenever a page lacked its own title. Google then guesses which location to show for brand searches, and it often guesses wrong.
Product titles follow strain, form, size, then brand. The searcher typed a strain and a format, so hand those back first: "Wedding Cake Live Resin Cart 1g | GreenLeaf" at 44 characters beats "Buy Weed Online | Best Colorado Dispensary | Premium Cannabis Products" at 71 characters with no product information. Google truncates displayed titles by pixel width, around 60 characters in practice, so the end of the title is the part that gets cut. Put the brand there. Google's guidance on title links also explains why stuffed, overlong and duplicated titles are the ones it most often rewrites.
Category and location titles read like the query. "Indica Flower in Denver" or "Dispensary in Longmont, CO" competes for something. A platform default like "Flower" competes for nothing. Pull strain, form and weight into the template as variables so a large catalog stays free of collisions without anyone writing titles by hand.
Meta descriptions win clicks, and they have no effect on rank. "Shop our wide selection of premium cannabis products" could sit on any menu in the country. "Live menu of indoor-grown flower with same-day pickup in Aurora, updated daily" belongs to one store. Lead with the specific claim and phrase it the way the query reads. Google's snippet documentation notes it replaces descriptions it considers a poor match. Fix money pages first and measure each rewrite in Search Console: same page, stable position, before and after click-through rate.
Headings and answer formatting
Headings on a cannabis page are an outline: one H1 that states the topic, H2s for major sections, H3s nested under the H2 they belong to, and no skipped levels. Pick a level for meaning and let CSS handle the look. Themes are the usual violator. WordPress and page-builder themes often wrap the logo in an H1 on every page, or print a hero H1 followed by a second H1 in the content. View source on a few pages, and if the same H1 text appears sitewide, fix the template by demoting that element to a div.
Write H2s as the sub-questions people actually search ("how long do edibles take to kick in") rather than clever labels. Each one becomes an entry point for its own long-tail query.
Put the answer in the first screen. Open with a direct answer in two or three sentences, then spend the rest of the page on caveats, mechanism and edge cases. That same pattern is what search features lift. People Also Ask boxes and paragraph featured snippets pull a question heading plus a self-contained 40 to 60 word answer: verdict first, qualifier second, no pronouns pointing back at earlier text. For process queries, use a numbered list under the heading and open each step with a verb ("Cure to 58 to 62 percent relative humidity"), since Google often shows only the step text. AI search tools (ChatGPT, Claude, Gemini, Perplexity and Google AI) quote the same kind of clean heading-plus-answer unit, so one format serves every surface.
Keep related questions together. Expand People Also Ask around one seed query, dedupe the questions by intent, put buying questions in an FAQ block on the category page, and fold educational ones into one long guide. Skip questions about medical effects, which go to health publishers and invite health-claim trouble.
Homepage, category and product pages
Each page type on a cannabis site has one job, and most on-page problems come from pages trying to do someone else's. The homepage targets your brand name plus one primary term that describes the whole business: "dispensary in Boulder" for a store, "THC gummies" for a gummy brand. Write the title as brand plus that term, match the H1, and add a few short blocks of real copy saying what you sell, where you are and who you serve. Then spend homepage links on the categories you need ranking, with descriptive anchors instead of "Shop Now".
Category pages are the durable asset. Searches like "live resin carts" carry volume no single SKU sees, and category URLs persist while products sell out. Add 150 to 300 words: what the category includes, the formats and potency ranges shoppers will find, and how to choose. A /concentrates/ page titled "Concentrates" with zero copy, for example, becomes rankable with a city-specific title, 220 words on shatter versus live resin versus rosin, and links from related guides.
Product pages run on one template. Agree on six slots and build them into the layout: an H1 of strain plus form, a unique description of at least 80 words, a spec table in plain HTML (THC and CBD, weight, strain type), a link to the current batch certificate of analysis, reviews that render as text, and related products from the same category. Potency shown as an image badge never reaches the index.
The description slot is where most stores lose. Paste a popular cart's description into Google in quotes and you will find it on dozens of menus, and Google shows only one copy. Write to the strain instead: lineage and breeder, dominant terpenes, tested potency, and sensory detail in a budtender's words. "Blue Dream crosses DJ Short Blueberry with Santa Cruz Haze. This run tested 21.4% THC with myrcene and pinene leading, a sweet berry nose over a piney exhale" cannot be reused under any other product. Keep medical claims out entirely. The FDA has sent warning letters to cannabis and CBD companies over treat-and-cure language, and the same words make Google more skeptical of the page. Rewrite top sellers first.
Schema markup that holds up
Schema markup on a cannabis site should be JSON-LD, generated by the template from the same fields the page displays. Google's structured data guidelines require the markup to describe content visible on the page.
- Store or LocalBusiness on each location page. Name, address, phone, geo coordinates and opening hours, character for character identical to the Google Business Profile, per Google's local business spec.
- Product on natively rendered product pages. Name matching the H1, image, the real description, brand, sku, and an offers block with price, priceCurrency and availability, as in Google's product structured data docs. THC has no dedicated property, so pass it as additionalProperty with a name of "THC" and a value like "82%". Only declare a price the visible page shows. Where pricing is restricted or behind a login, drop the property.
- BreadcrumbList sitewide. One ListItem per level, mirroring the visible trail exactly. When it validates, Google often shows "Home › Concentrates › Live Resin" in place of a raw slug, following the breadcrumb spec.
- FAQPage where a real FAQ exists. Google limits FAQ rich results to well-known government and health sites, so a dispensary will not get the dropdowns. The markup is still a clean machine-readable copy of your answers, as long as it mirrors visible text.
Products inside a Dutchie or Jane iframe cannot be marked up on your domain, because that content is served from the provider's host. Validate one page per template in the Rich Results Test and the Schema Markup Validator at validator.schema.org. One trailing comma kills a whole block with no visible error, so recheck after theme updates and migrations.
Crawling: robots.txt, sitemaps and filters
Crawling problems on cannabis sites mostly come from the menu, which can mint more URLs than the rest of the site combined. Start with robots.txt, which needs three directives: User-agent, Disallow and Sitemap. A sane dispensary file blocks /cart/, /checkout/ and internal search (/?s= on WordPress), then points to the sitemap. Mind the trailing slashes. Disallow matches by prefix, so a careless "Disallow: /c" blocks /cart/, /cbd-gummies/, /concentrates/ and /contact in one character. Never block CSS or JavaScript files.
Disallow stops crawling but leaves indexing open, and blocking a noindexed page means Google can never see the noindex. To remove a page, let it be crawled and serve noindex or a 404. Check after every relaunch, because sites still go live with the developer's "Disallow: /" in place.
Faceted filters are the biggest crawl trap. A /flower category with 30 brands, three types, four THC ranges, five weights and a couple of sort orders produces tens of thousands of near-identical URLs, each one fetchable. The fix is layered. Canonical every parameter URL to its base category. Add robots.txt patterns such as "Disallow: /*?*sort=" for sort orders and stacked combinations Googlebot should never touch. Promote the few filters with real demand and stable inventory (indica flower, live resin carts, a house brand) to static pages like /flower/indica/ with their own title and copy. Google's crawl budget guidance covers the same logic for large sites.
The XML sitemap lists only canonical, indexable, 200-status URLs on your own host, generated automatically by the CMS. Leave out redirects, parameter variants and noindexed pages. Google reads lastmod only when it is honest, and embedded menu products cannot be listed at all. Submit it in Search Console and on a Sitemap line in robots.txt, per Google's sitemap overview.
Then check where Googlebot actually spends its time. The Crawl stats report under Settings shows fetches, errors and redirects. Server logs show the same thing per URL, and our guide to using log files to improve cannabis crawl efficiency walks through reading them. Remember AI crawlers too. OpenAI's crawler documentation lets you allow OAI-SearchBot for ChatGPT search while blocking GPTBot for training, and plenty of cannabis sites block both by accident. Our walkthrough on running an AEO audit on a cannabis website covers testing AI crawler access step by step.
Fixing indexing problems
Indexing problems on a cannabis site are diagnosed by reason, and the raw count of unindexed pages tells you almost nothing. A menu throws off parameter URLs nobody needs indexed. Open Indexing, then Pages, in Search Console, export the list, filter to templates that earn revenue (strain, category, location pages) and work one reason at a time.
- Crawled, currently not indexed is a quality verdict. Google fetched the page and decided the index already holds enough copies. On cannabis sites this fills with breeder-pasted strain copy, products that differ only in THC percentage and city pages with a swapped name. The page needs material its near-duplicates lack (your photos, staff notes, test results, pickup details) or it needs to be merged into a page that has it.
- Discovered, currently not indexed is a crawl priority problem. Google knows the URL, usually from the sitemap, and has not spent the visit. Link to stranded pages from pages that already rank, and cut junk URLs so the crawl is worth making.
- Duplicate without user-selected canonical and Google chose different canonical than user mean your signals disagree. Canonicals, internal links and the sitemap must all name the same version of each page.
Rule out self-inflicted blocks before any content work: a staging noindex left on, a Disallow still covering /shop/, an age gate serving crawlers an interstitial. Run a sample URL through URL Inspection, open the crawled HTML and search it for a product name. If the text is missing, quality work will not register.
Say a store has 240 strain pages and 61 indexed, with the rest split across crawled-not-indexed, discovered-not-indexed and ?sort= duplicates. Rewriting the 30 best sellers, 301ing discontinued strains to their categories and canonicalizing the sort URLs addresses all three buckets at once. Then press Validate Fix and recheck monthly.
Age gates and crawlers
Age gates are the most cannabis-specific technical risk, because a crawler cannot click "I am 21". How the gate is built decides what Google sees. A gate drawn as an overlay on top of a fully loaded page usually does no harm: the product text, headings and links are all in the HTML underneath. A gate that redirects to a separate URL, or holds back the page content until a click sets a cookie, hands Googlebot and every AI crawler the gate and nothing behind it.
Test it directly. Fetch a product page with a command-line tool or a crawler with no cookies, then search the raw HTML for a product name and a price. If the content is missing, rebuild the gate as an overlay on top of complete markup.
Gates also cause mobile and speed trouble. A gate injected into the page flow shifts the layout and hurts CLS. Google is more lenient with legally required interstitials than with marketing popups, so keep the gate a clean overlay and keep the newsletter popup off the landing view. Our guide to age-verification requirements for cannabis sites covers the rules side.
Menus and JavaScript rendering
Menu rendering is where many dispensary sites quietly lose every product search. Most menus come from Dutchie or Jane, installed as an iframe or injected with JavaScript. Iframe content counts toward the provider's domain, and injected menus often never make it into the indexable page. Viewed the way Googlebot sees it, your /menu/ page is a header, a footer and a hole. Our short answer on how menu platforms like Dutchie affect dispensary SEO sums up the trade-off.
Google does render JavaScript, but its JavaScript SEO documentation describes rendering as a separate step that can happen after the HTML crawl, and pages get judged on bare HTML in between. Many AI crawlers do not run JavaScript at all. So anything that must rank (product copy, category text, internal links) belongs in the initial HTML response. Check URL Inspection's crawled page, or load the page with JavaScript disabled. Whatever survives is what crawlers are guaranteed to get.
Links need the same treatment. A navigation item that is a click handler with no href, or a load-more button that never changes the URL, gives Googlebot nothing to follow. Google's link best practices want a tags with an href. Keep infinite scroll for shoppers if you like, but pair it with real paginated URLs, each carrying a self-referencing canonical. Pointing page 2 and beyond at page 1 tells Google those pages are duplicates and cuts off every product linked only from them.
There are two fixes, depending on budget:
- Native menu. Pull product data from the provider's API and render each category and product as a real, server-rendered URL on your domain with its own title, copy and schema.
- Hybrid around the embed. Keep the iframe for browsing and checkout, and build indexable category pages around it: 150 to 300 words of copy, a short FAQ and a deep link into the filtered menu. It can ship in weeks.
For React or Vue storefronts, server-side rendering or build-time prerendering puts content pages into HTML while cart state and store pickers stay client-side. Our guide on handling JavaScript rendering on cannabis sites goes further into choosing between them.
Speed, Core Web Vitals and mobile
Speed on a cannabis site is graded on real phones, so measure that before fixing anything. Google's Core Web Vitals set three thresholds at the 75th percentile of real Chrome visits: Largest Contentful Paint at 2.5 seconds or less, Interaction to Next Paint at 200 milliseconds or less, and Cumulative Layout Shift at 0.1 or less. PageSpeed Insights shows field data from the Chrome User Experience Report on top and a Lighthouse lab audit below. When they disagree, trust the field number and use the lab report to find out why.
- Server first. On the shared cPanel hosting many small stores use, full-page caching usually fixes slow TTFB before any hosting upgrade does. Confirm brotli or gzip compression and long cache headers are actually on, and put static files behind a CDN.
- Images next. Strain photography arrives at full phone resolution. A 4.2MB hero resized to its 1600-pixel display width and saved as WebP lands around 174KB. Use srcset so phones get phone-sized files, preload the hero, lazy-load only what sits below the fold, and give every img width and height attributes so the page does not jump.
- Scripts last, and hardest. Age gate, chat widget, loyalty popup, menu embed and two analytics tags all compete for the main thread, which is what fails INP. Defer what can wait, load chat on first interaction, delete tags nobody reads.
Mobile parity matters as much as mobile speed. Under mobile-first indexing, the smartphone crawler's fetch is the version Google ranks. A mobile theme that drops category descriptions or skips the Product schema partial has deleted them for ranking purposes. Accordions and tabs still count. After any redesign, compare the smartphone fetch in URL Inspection against the desktop page, and test on a mid-range phone over cellular.
Site architecture, URLs and internal links
Site architecture decides which cannabis searches you can compete for at all. Head terms like "live resin carts" are won by category pages, and a category page only exists if the structure creates it. Name categories from keyword data, in the words shoppers type (edibles, pre-rolls, vape carts), and keep in-house labels one level down.
Hold every page you care about within three clicks of the homepage; Screaming Frog's crawl depth report shows the real number. Splitting a long menu into real subcategories (flower by type, carts by hardware, edibles by format) turns one 38-page pagination walk into many short ones.
URLs mirror the tree. Lowercase, hyphens, short slugs that name the topic, and no dates in blog slugs: /flower/indica/ and /blog/how-to-store-cannabis/. Leave room for growth with a pattern like /dispensaries/state/city/ before the second location opens, because forced restructures arrive with a full redirect map attached. Brands selling across countries need hreflang with reciprocal annotations on every page in the set; note that the United Kingdom code is en-gb, and en-uk fails silently.
Internal links do the routing. Organize content as hub and spoke: each topic has a hub (a category or pillar guide), every spoke links up to its hub and across to two or three siblings, and the hub links down to all of them. Use descriptive anchors that vary naturally. A related-products widget that puts "buy cannabis flower online" on 340 posts is the kind of repeated exact-match pattern Google's spam policies describe. Find your strongest senders in Search Console by clicks, link from them to the pages that need to rank.
Duplicate and thin content
Duplicate content on a cannabis store draws no penalty, but it still costs you: Google clusters copies, shows one, and picks the version itself. Google's guide to consolidating duplicate URLs lays out the tools. Fix the sources in this order:
- Host variants. http and https, with and without www: three of the four 301 to the fourth in one hop, with trailing slashes settled at the same time.
- Parameters. Sort orders, filters, utm and fbclid tags. Every indexable page carries a self-referencing canonical, and variant URLs point at the clean base. Never canonical one distinct strain to another, and never pair noindex with a canonical to a different page.
- Self-competition. A "Denver dispensary" page and a "dispensary in Denver" page, two posts on one question, or three strain URLs for one Blue Dream. Merge into the strongest URL, 301 the rest, and mention alternate names on the survivor.
Thin content needs one verdict per page. Work the overlap of short pages and zero clicks over twelve months. Expand pages for things you sell, merge pages circling one intent with 301s, and remove pages that never earned anything. Merging usually beats deleting, because the survivor keeps the links and history the old pages collected.
Out-of-stock products keep their URLs. Cannabis inventory rotates by harvest, and deleting a page every sellout resets what it earned. Keep it live and indexable, set availability to OutOfStock in the Product schema, show in-stock alternatives, and flip it back on restock day. Discontinued products with links or rankings get a 301 to the closest substitute or parent category. Pages with no equity get a 410. Never sweep every dead product to the homepage, which Google treats as a soft 404.
Redirects, HTTPS and migrations
Redirects and migrations are where cannabis sites lose the most traffic in a single day, usually during a menu provider switch. Say a store moves from /shop/product-name to /menu/product-name and roughly 300 product URLs start returning 404s. One pattern rule (anything under /shop/ 301s to the same slug under /menu/, with a category fallback for products that did not carry over) prevents it, but only if someone writes the URL map before launch day.
Use 301s for permanent moves and keep 302s for changes with an end date. Google's redirects documentation covers how each is treated. Chains build up over the years (http to https, to www, to a new /shop/ path), and every hop adds load time and another point of failure. Screaming Frog's Redirect Chains report lists each one. Collapse each chain to one 301, then update internal links to final URLs so your own menus stop firing redirects.
Sort dead URLs by intent: moved or replaced pages get a 301, pages gone for good keep a 404 or return a 410. Soft 404s, like empty "no products found" categories returning 200, get real content or an honest error code. HTTPS is part of the same plumbing: a free Let's Encrypt certificate is enough, HSTS goes on with a short max-age first, and mixed content usually traces to an old theme's hardcoded http:// image URLs.
Every migration, theme update and menu-provider change quietly reintroduces old problems, so rerun the full crawl and Search Console review every quarter and after every launch. If you would rather have the whole site checked in one pass, with fixes ranked by what they cost you, our cannabis SEO audit covers every layer in this guide.
Key takeaways
- Work in the order a crawler meets the site: access, rendering, indexing, then titles, headings, schema and copy.
- Dutchie and Jane embeds put products on the provider's domain; a native menu or indexable category pages around the embed bring them back.
- Age gates belong as an overlay on top of complete HTML, never as a redirect or a click-to-load wall.
- Canonical filter URLs to their base category, block endless sort and facet spaces, and promote only filters with real demand to static pages.
- Read the reason in the Search Console Pages report: crawled-not-indexed is quality, discovered-not-indexed is crawl priority, duplicate reasons are signal conflicts.
- Templates carry the on-page work: unique titles, one H1, HTML spec tables, schema generated from page fields and original product descriptions.
- Write the redirect map before any migration or menu switch, and collapse chains to a single 301.
Frequently asked questions
Can Google index products in a Dutchie or Jane menu embed?
Not on your domain. Iframe menus are served from the provider's host, so any search value from those product pages goes to the provider, and injected menus often never reach the indexable page. To rank for products, render them as real pages on your own site through the provider's API, or build indexable category pages with unique copy around the embed.
Does an age gate hurt SEO for a cannabis website?
It depends on how it is built. An overlay drawn on top of a fully loaded page usually leaves the content readable to crawlers. A gate that redirects to its own URL or withholds content until someone clicks shows crawlers only the gate, which can leave key pages blank in Google and in AI search tools.
Is there a duplicate content penalty for using breeder strain descriptions?
There is no penalty, but Google filters copies and shows only one version of identical text, usually from the biggest site. A store running the same breeder or brand description as dozens of other menus effectively becomes an invisible duplicate. Rewriting top sellers with lineage, terpenes, tested potency and sensory detail fixes it.
Should a dispensary add FAQ schema if Google no longer shows FAQ rich results?
It is still worth adding where a real FAQ is visible on the page. Google limits FAQ rich results to well-known government and health sites, so the snippet will not change, but the markup gives search engines a clean machine-readable copy of your answers. Mirror the visible text exactly and never mark up hidden content.
How often should a cannabis site run a technical SEO check?
Review Search Console's Pages report monthly and run a full crawl every quarter. Add an extra check after every theme update, platform migration or menu-provider change, since those events most often reintroduce broken titles, missing schema, redirect chains and blocked pages.
Sources
- Influencing your title links in search results, Google Search Central. Covers how Google builds and rewrites title links.
- Control your snippets in search results, Google Search Central. Covers meta descriptions and when Google replaces them.
- Featured snippets and your website, Google Search Central. Covers how featured snippets are chosen and controlled.
- FDA regulation of cannabis and cannabis-derived products, including CBD, U.S. Food and Drug Administration. Covers FDA's position and warning letters on health claims.
- General structured data guidelines, Google Search Central. Covers the rule that markup must match visible content.
- Local business structured data, Google Search Central. Covers LocalBusiness and Store properties.
- Product structured data, Google Search Central. Covers Product, Offer and availability properties.
- Breadcrumb structured data, Google Search Central. Covers BreadcrumbList markup.
- FAQ structured data, Google Search Central. Covers FAQPage markup and which sites are eligible for FAQ rich results.
- Rich Results Test, Google. Tests whether structured data parses and which features a page is eligible for.
- Introduction to robots.txt, Google Search Central. Covers directives and the difference between blocking crawling and indexing.
- Crawl budget management for large sites, Google. Covers faceted URLs and crawl efficiency.
- What is a sitemap, Google Search Central. Covers sitemap contents and limits.
- Overview of OpenAI crawlers, OpenAI. Covers OAI-SearchBot, GPTBot and their robots.txt controls.
- Understand JavaScript SEO basics, Google Search Central. Covers how Google crawls, renders and indexes JavaScript pages.
- Link best practices for Google, Google Search Central. Covers crawlable links and anchor text.
- Web Vitals, web.dev (Google). Covers LCP, INP and CLS thresholds.
- PageSpeed Insights, Google. Reports field and lab performance data for a URL.
- Mobile-first indexing best practices, Google Search Central. Covers content and markup parity between mobile and desktop.
- Tell Google about localized versions of your page, Google Search Central. Covers hreflang codes and reciprocal annotations.
- Spam policies for Google web search, Google Search Central. Covers doorway pages and link spam, including keyword-rich anchors.
- How to specify a canonical URL, Google Search Central. Covers rel=canonical, redirects and other consolidation methods.
- Redirects and Google Search, Google Search Central. Covers permanent and temporary redirects.
Want this done for your brand?
We build cannabis & CBD search visibility with full transparency, for dispensaries, brands, and MSOs.
Get a free cannabis SEO audit ›