Other services · website design & SEO

    Get found. Then get chosen.

    Sites a crawler reads with JavaScript switched off and a buyer cannot scroll past. Prerendered, mapped, canonicalised, measured, and served from the city your visitor is standing in.

    Real HTML, not a JS shellOne canonical per pageCore Web Vitals in the green
    The flagship: event marketing

    16

    routes, all prerendered

    0

    pages that need JS to exist

    14 kB

    this document, over the wire

    view-source:/services/website-design-seo
    1<!doctype html><html lang="en">
    2<title>Website Design & Technical SEO Services | MyWebGlory
    3<link rel="canonical" href="https://mywebglory.com/services/website-design-seo"/>
    4<meta property="og:image" content="…MyWebGlory_purple.png"/>
    5<script type="application/ld+json">{"@type":"Service"}
    6<h1>Get found. Then get chosen.</h1>

    Every line above exists before a script runs. Check it yourself.

    The uncomfortable truth

    Get found first.

    Nobody types your URL. They type a problem into Google and trust whatever surfaces. Everything below is the engineering that decides whether you are on that screen.

    We still make them beautiful. Beauty is the closer, not the strategy.

    Prerendering · exhibit A

    So every route ships as finished HTML.

    This site is React. It is also twenty-one real documents on disk, because a headless Chrome renders every route at build time and writes the result out. The framework is our convenience. The HTML is the product.

    Fetched with JavaScript disabled

    curl --disable-javascript https://competitor.example/what most React sites serve
    <body><div id="root"></div>
    <script type="module" src="/assets/app-3f2c.js">
    # words of body copy: 0
    # headings found: 0
    # JSON-LD blocks: 0

    Nothing to read, nothing to rank. The content is a promise the crawler has to come back for.

    curl --disable-javascript https://mywebglory.com/services/website-design-seowhat this URL serves
    <main><h1>Get found. Then get chosen.</h1>
    <p>Sites a crawler reads with JavaScript…
    # words of body copy: 2,140
    # headings found: 1 h1 · 10 h2 · nested h3
    # JSON-LD blocks: 3 · Organization, Service, BreadcrumbList

    Identical to what you are looking at, minus the animations. That is the whole trick.

    Why the render queue is the whole story

    The render queue

    Google does execute JavaScript. It just does it later, on a second pass, out of a queue it will not show you.

    A JavaScript shellindexed days to weeks after the crawl
    fetch HTMLsees an empty divrender queueheadless renderindex
    Prerendered HTMLindexed on the same visit
    fetch HTMLparse the finished documentindex

    The gap in the middle of the first lane is where a new page sits, crawled and not indexed, while somebody asks why the launch is not showing up. Static HTML deletes the gap. It also deletes every failure mode underneath it: a script that four-oh-fours, a hydration error, a consent wall, a rate limit on the API the page needed to render its own headline.

    This page's heading outline

    h1Get found. Then get chosen.
    h2Get found first.
    h2So every route ships as finished HTML.
    h3Fetched with JavaScript disabled
    h3Why the render queue is the whole story
    h2Then a generated map hands Google all 21.
    h3robots.txt, and what it is actually for
    h2Each one at exactly one address.
    h2

    a level is never skipped, and there is exactly one h1

    Semantics, where accessibility and ranking are the same job

    One h1 per document, and it is not a copy of the title tag: the title answers the query, the h1 greets the human.

    Levels never skip. An h4 under an h2 tells a screen reader and a parser that a section is missing.

    Real landmarks: header, nav, main, footer. A crawler and a screen reader both use main to find the content and skip the furniture.

    Alt text describes the picture, not the keyword. Decorative photography carries alt equal to empty string so it is skipped instead of narrated.

    Links say where they go. Twelve links reading here on one page is twelve wasted anchors.

    Contrast at 4.5:1 on body copy. The same fix that passes WCAG keeps the page readable on a phone in daylight.

    Sitemap structure · generated, never maintained

    Then a generated map hands Google all 21 of them.

    Not a plugin's guess and not a file somebody updated in March. The build reads the route table, walks the source files, and writes the map. Forgetting a page stops being possible.

    dist/sitemap.xml · rendered as a tree21 URLs · 0 hand-written
    locchangefreqlastmod
    mywebglory.com/weekly2026-07-31
    ├── event-marketing/weekly2026-07-31
    ├── how-it-works/weekly2026-07-31
    ├── production/weekly2026-07-30
    ├── case-studies/weekly2026-07-29
    ├── pricing/weekly2026-07-29
    ├── services/
    │ ├── website-design-seo/monthly2026-07-31
    │ ├── custom-software/monthly2026-07-31
    │ ├── social-media/monthly2026-07-28
    │ ├── email-marketing/monthly2026-07-28
    │ ├── ads-campaigns/monthly2026-07-28
    │ └── graphic-design/monthly2026-07-28
    ├── blog/weekly2026-07-27
    │ ├── ultimate-guide-event-marketing/monthly2026-06-18
    │ ├── event-marketing-playbook/monthly2026-06-02
    │ ├── build-authority-event-content/monthly2026-05-21
    │ └── trade-show-roi/monthly2026-05-09
    ├── about/monthly2026-07-26
    ├── contact/monthly2026-07-26
    ├── faq/monthly2026-07-26
    └── privacy/yearly2026-04-14

    every entry resolves 200, is canonical, and is indexable. nothing else belongs in here.

    public/robots.txtserved, not guessed
    User-agent: Googlebot
    Allow: /
    User-agent: *
    Allow: /
    Sitemap: https://mywebglory.com/sitemap.xml
    # the sitemap line is absolute, and the file exists

    robots.txt controls crawling, never indexing. a blocked URL can still be indexed from a link, without a description.

    at scale · sitemap index50,000 URL ceiling
    <sitemapindex>
    <sitemap><loc>/sitemap-pages.xml</loc>
    <sitemap><loc>/sitemap-blog.xml</loc>
    <sitemap><loc>/sitemap-services.xml</loc>
    <sitemap><loc>/sitemap-fr.xml</loc>
    </sitemapindex>

    split by section long before the ceiling, so Search Console tells you which section broke.

    robots.txt, and what it is actually for

    Generated, never maintained

    The build reads the route table and writes sitemap.xml from it. Adding a page to the router adds it to the map in the same commit. A human forgetting is no longer one of the failure modes.

    lastmod from the filesystem

    Each entry takes its date from the modification time of the source file that renders it, not from the day of the build. A sitemap where every URL changed today is a sitemap Google learns to ignore.

    changefreq that matches reality

    Weekly on the pages we actually edit, monthly on the service pages, yearly on privacy. It is a hint, not a command, and the hint is only worth giving if it is true.

    Only canonical, only 200

    No redirects, no noindex, no parameter variants, no URLs that four-oh-four. A sitemap is a list of pages you are willing to be judged on.

    The Crawler's CopyFetched with JavaScript disabled · 200 OK · 19 kB

    Every route is a document before it is an app.

    MyWebGlory ships twenty-one prerendered documents, one canonical URL per page, a sitemap generated from the router at build time, and Organization, Service and Breadcrumb schema attached to the templates rather than sprinkled by hand.

    The same team fills B2B virtual event rooms for a living: 50+ events marketed, 40,000+ attendees hosted, 60%+ of registrants showing up live against a 35% industry average.

    your page, as Googlebot receives it. no scripts, no shell, no second request, no waiting.

    What the map cannot fix

    A sitemap is a hint, not an instruction. It gets a page discovered; it never gets a page indexed. Indexing is earned by the page being worth a slot: distinct from its neighbours, linked to from inside the site, fast enough to be worth rendering, and about something a person actually typed.

    Which is why the crawl we run at the start of an engagement reports two numbers, not one: how many pages exist, and how many of them deserve to.

    discoverycrawl budgetindex coverageinternal links

    URL hygiene · one page, one address

    Each one at exactly one address.

    Two URLs serving one page is not a tidiness problem. It is two pages splitting the same links, the same authority and the same click data, and neither of them winning.

    curl -sIL https://competitor.example/Pricing4 hops
    HTTP/1.1 302 Found http://competitor.example/pricing
    HTTP/1.1 301 Moved https://competitor.example/pricing
    HTTP/1.1 301 Moved https://www.competitor.example/pricing
    HTTP/1.1 301 Moved https://www.competitor.example/pricing/
    HTTP/1.1 200 OK
    canonical → https://competitor.example/pricing (the 302 target)

    four round trips before a single byte of content. on a 3G handset that is most of a second, spent on nothing.

    curl -sIL https://mywebglory.com/Pricing1 hop
    HTTP/3 301 Moved Permanently https://mywebglory.com/pricing
    HTTP/3 200 OK · cf-cache-status: HIT
    canonical → https://mywebglory.com/pricing
    sitemap → https://mywebglory.com/pricing
    nav links → /pricing
    # four sources of truth, one string

    one permanent redirect straight to the final address, then a self-referencing canonical that agrees with it.

    One canonical, pointing at itself

    Every page declares an absolute, self-referencing canonical that matches the URL actually serving 200. A canonical pointing somewhere else is a request to be de-indexed, and plenty of sites make it by accident.

    Trailing slash decided once

    /pricing and /pricing/ are two URLs to a crawler. Pick one, 301 the other, and make the canonical, the sitemap, the internal links and the CMS all agree. Two half-ranked copies beat neither.

    301, not 302

    A 302 says keep the old URL indexed and expect it back. Permanent moves get 301 or 308. We only reach for 302 when something genuinely comes back next week.

    No chains, no loops

    http to https to www to slash is four hops and roughly half a second before a byte of content arrives. Every redirect resolves in one hop, straight to the final URL.

    Pagination stays indexable

    Page two of a listing is its own URL with its own self-referencing canonical. Canonicalising it back to page one hides everything after the first ten results. rel=prev and rel=next stopped being a Google signal in 2019; internal linking carries it now.

    Parameters normalised

    Casing, index.html, session ids and tracking parameters all resolve to the same clean address. Whatever survives gets a canonical rather than a crawl budget.

    A woman smiling at her phone at a cafe table with an open laptop beside her.
    she will never see a canonical tag. she only ever feels the half second it saved her.

    Metadata & structured data

    Wearing metadata written to be clicked.

    Ranking gets you onto the screen. The title tag and the description are what decide whether the thumb stops on you or on the result underneath.

    How the result renders

    Before

    competitor.example › home

    Home | Acme Digital Ltd | Welcome to our website

    Acme Digital Ltd is a full-service agency founded in 2011 offering a wide range of solutions to help businesses…

    52 characters of brand before a single word the searcher typed

    After

    mywebglory.com › services › website-design-seo

    Website Design & Technical SEO Services | MyWebGlory

    Static sites crawlers read with JavaScript off: prerendered routes, generated sitemaps, clean canonicals, green Core Web Vitals, edge caching worldwide.

    the query answered in the first four words · breadcrumb from BreadcrumbList, not from the URL

    The social card

    1200 x 630

    mywebglory.com

    Website Design & Technical SEO Services | MyWebGlory

    Static sites crawlers read with JavaScript off.

    title
    50 to 60 characters

    roughly 600 px before Google rewrites it. Query first, brand last, separated by a pipe.

    meta description
    150 to 160 characters

    not a ranking factor, very much a click-through factor. Write the answer, not the mission statement.

    og:image
    1200 x 630, under 8 MB

    1.91:1. Absolute https URL. Text large enough to survive a phone-sized preview.

    twitter:card
    summary_large_image

    plus twitter:title, description and image. LinkedIn and Slack read the Open Graph tags.

    og:locale
    one per language

    with og:locale:alternate for the rest of the set, matching the hreflang cluster exactly.

    og:image:alt
    always

    the social preview is an image, and images get described.

    Which structured data Google actually consumes

    JSON-LD, and what Google does with it

    Shipping schema is easy. Knowing which of it ever reaches a searcher's eye is the part that separates a checklist from a strategy.

    Organization

    Feeds the knowledge panel: name, logo, founder, contact, sameAs profiles.

    visible rich result
    BreadcrumbList

    Replaces the raw URL in the result with a readable breadcrumb trail. Visible, immediately.

    visible rich result
    Article / BlogPosting

    Eligible for Top Stories, Discover and article rich results. Needs a real author and dates.

    visible rich result
    FAQPage

    Since August 2023 the accordion only shows for authoritative health and government sites. Ship it for the entity graph, not for the pixels.

    entity context only
    Service

    Not a rich result type. It tells Google what this page sells and how it relates to the organisation.

    entity context only
    LocalBusiness

    Context for the map pack: area served, hours, contact. Rendering depends on the query.

    entity context only
    JSON-LD in the head, never microdata scattered through the body, and never describing something the page does not contain. Marking up a review that is not on the page is how a site earns a manual action. This page ships Organization, Service and BreadcrumbList. View source.

    Core Web Vitals · the numbers Chrome reports on you

    Loading before a visitor decides to leave.

    Every Chrome user quietly sends these three numbers home. They are the only performance figures Google grades you on, and they are measured on your visitors' phones, not on your laptop.

    LCP

    Largest Contentful Paint

    2.5 s or better

    over 4.0 s is poor

    when the biggest thing above the fold finishes painting. On a marketing page it is almost always the hero image or the h1.

    INP

    Interaction to Next Paint

    200 ms or better

    over 500 ms is poor

    replaced FID in March 2024, and it is harsher: it measures the worst interaction of the visit, not the first.

    CLS

    Cumulative Layout Shift

    0.1 or better

    over 0.25 is poor

    how much the page moves under a thumb. Almost always an image, an ad slot or a font with no reserved box.

    The waterfall we build toward

    network · /services/website-design-seo · Moto G, Fast 3GLCP 1.1 s
    GET /services/website-design-seodocument48 ms
    hero-1600.avifimage212 ms
    index-BI4039yt.cssstylesheet62 ms
    Inter-latin.woff2font88 ms
    index-BwGANaVv.jsscript340 ms
    calendly widget.jsthird party280 ms
    edge HIT, no origin round trip
    preload, fetchpriority high, decoding sync. This is the LCP element.
    render blocking on purpose, 14.5 kB after brotli
    preconnected, subset to latin, font-display swap
    type=module, deferred. It hydrates a page that already painted.
    async, after paint, never in the critical path

    the image that becomes LCP starts downloading in the same breath as the stylesheet. the application bundle arrives after the page has already painted.

    The LCP image is preloaded with fetchpriority=high and is never lazy loaded. loading=lazy on a hero image is the fastest way to lose a whole second, and it is on most sites we audit.

    Every image, video and embed carries width and height, or an aspect-ratio box. The space is reserved before the bytes arrive, which is most of CLS solved for free.

    Fonts: preconnect to the font origin, subset to the characters actually used, font-display swap so text paints in a fallback instead of hiding.

    JavaScript is deferred and the page does not need it. Hydration is an upgrade, never the thing that makes the h1 appear.

    Third parties load after paint, in an idle callback where possible. One chat widget can cost more INP than the entire application.

    Measured at the 75th percentile of real Chrome visits over 28 days, per URL group. Your laptop on office wifi is not the measurement.

    One rebuild · week 0 against week 6
    Site Audit · field data, 28 day window"virtual event marketing agency"

    Before · as we found it

    invisible
    #38Google · page 4

    Core Web Vitals · p75 field data

    LCP4.8 sPoor
    INP460 msNeeds work
    CLS0.31Poor

    Routes indexed

    6 of 14 · 3 duplicate variants competing

    Weight, first view

    4.1 MB · 62 requests · 1.9 MB of unused JS

    After · week 6

    shipped
    #3Google · page 1up 35 spots

    Core Web Vitals · p75 field data

    LCP1.2 sGood
    INP110 msGood
    CLS0.02Good

    Routes indexed

    14 of 14 · one canonical each

    Weight, first view

    0.4 MB · 14 requests · AVIF hero, brotli everything

    Every route prerendered to real HTML, so the crawler stopped waiting on a render queue.

    Three duplicate URL variants collapsed into one canonical each, with 301s instead of 302s.

    sitemap.xml generated from the route table, lastmod taken from the source files.

    The hero image preloaded at fetchpriority high, and un-lazy-loaded.

    Title tags rewritten to answer the query, brand moved to the end.

    Organization, Service and Breadcrumb JSON-LD attached to every template.

    position #38 was a rendering problem, not a content problem. The words were already good.

    Build, weight & the edge

    Built small, and served from the nearest city.

    Two numbers decide how a site feels: how many bytes it asks for, and how far those bytes travel. We hold both down, and we let you watch the build that proves it.

    npm run deploygreen
    $ vite build
    vite v5.4.19 building for production...
    2,841 modules transformed.
    dist/index.html2.20 kBgzip 0.94 kB
    assets/index.css104.59 kBbr 14.47 kB
    assets/index.js992.78 kBbr 198.41 kB
    built in 8.14s
    sitemap.xml generated from the route table
    react-snap · crawling every route with headless Chrome
    21 documents written to dist/**/index.html
    wrangler pages deploy dist --project-name=mywebglory
    uploaded 214 files · live on the edge in 41s

    a copy fix is live worldwide in under two minutes. that is why the pages that win are the ones that got edited twenty times.

    cf-cache-status · TTFB by city330+ cities
    ParisHIT11 ms
    LondonHIT14 ms
    New YorkHIT19 ms
    São PauloHIT28 ms
    SingaporeHIT31 ms
    SydneyHIT36 ms
    cache hit ratio98.6%

    HTML revalidates on every request so a deploy is instant everywhere. hashed assets never revalidate at all.

    Every byte, twice compressed

    What actually goes over the wire

    filerawgzipbrotlisaved
    index-BwGANaVv.js992.8 kB250.4 kB198.4 kB80% off
    index-BI4039yt.css104.6 kB17.8 kB14.5 kB86% off
    website-design-seo.html123.9 kB23.0 kB19.0 kB85% off

    One unprocessed portrait sitting in this very repository is 2.5 MB. The same photograph, as AVIF, at the size it actually displays, is under 60 kB. That single comparison is the entire argument for an image pipeline.

    Code split per route

    Dynamic imports at the route boundary, so the pricing page never downloads the blog's renderer. Rollup splits on those boundaries automatically and hoists what is genuinely shared.

    Tree shaken on purpose

    Named ESM imports only. One named icon import ships one icon; a namespace import ships the whole library. That single habit is worth more than most build flags.

    Compressed twice

    gzip is the floor and brotli level 11 is the ceiling. Brotli takes another 21% off our JavaScript and 19% off our CSS, at the edge, for nothing.

    Images in this decade's formats

    AVIF first, WebP as the fallback, in a picture element with a responsive srcset and a sizes attribute so a 375 px phone never downloads a 2560 px hero.

    Hosting

    Cloudflare Pages, because a static site deserves an origin that cannot fall over.

    Cloudflare Pages. One deploy pushes the whole site to a network spanning 330+ cities in 120+ countries, so the nearest copy is a few milliseconds away wherever the query came from.

    Content-hashed assets served immutable for a year. The hash changes when the bytes change, so there is no cache to purge, ever.

    HTML served fresh with a revalidation check, so a copy fix is live worldwide the second the deploy finishes.

    Atomic deploys with instant rollback to any previous build. A bad release is undone in one click, not in another build cycle.

    HTTP/3 over QUIC and TLS 1.3, so a lossy mobile connection stops paying for head-of-line blocking.

    Unmetered DDoS mitigation in front of it, and with a static site there is no origin left to knock over anyway.

    one canonical per pagetrailing slashes normalisedprerendered HTMLsitemap from the route tablefetchpriority=highCLS under 0.1INP under 200 mshreflang with x-defaultbrotli at the edgeimmutable content hashesno redirect chains302s promoted to 301sAVIF with a WebP fallbacktitles that answer queriesalt text that describesrobots.txt that means it
    robots.txt that means italt text that describestitles that answer queriesAVIF with a WebP fallback302s promoted to 301sno redirect chainsimmutable content hashesbrotli at the edgehreflang with x-defaultINP under 200 msCLS under 0.1fetchpriority=highsitemap from the route tableprerendered HTMLtrailing slashes normalisedone canonical per page

    International · hreflang done properly

    In whatever language the query was typed in.

    We shipped mydropai.com in 26 languages across 40+ pages, every one of them prerendered and every one carrying its full hreflang set. Here is what that actually takes.

    The hreflang cluster, as it ships

    head of mydropai.com/features/ · 6 of 27 alternates shown26 languages
    hreflanglanguagehrefwhy
    x-defaultFallbackhttps://mydropai.com/features/every unmatched language lands here
    enEnglishhttps://mydropai.com/features/self-referencing, as required
    frFrenchhttps://mydropai.com/fr/fonctionnalites/the slug is translated too
    esSpanishhttps://mydropai.com/es/funciones/es, not es-ES, until Spain differs
    pt-BRPortuguese (BR)https://mydropai.com/pt-br/recursos/region split earns its keep here
    deGermanhttps://mydropai.com/de/funktionen/one of 26 in the cluster

    27 entries on every page in the cluster, including the page's own, plus x-default. Miss one and Google throws the whole set away.

    The set is bidirectional

    Every page in a language cluster lists every other page in that cluster, including itself. A one-way reference is thrown away silently, which is why most broken hreflang looks fine in the HTML.

    x-default is not optional

    It is the answer for the 60 languages you did not translate. Leave it out and Google picks for them.

    One stable URL per locale

    Not a cookie, not an IP sniff, not a JavaScript redirect. A crawler in California has to be able to reach the French page and stay on it.

    The metadata gets translated too

    Title, description, Open Graph, alt text, the JSON-LD name and description, and the slug. A French page wearing an English title tag ranks for nothing in French.

    Region codes you can defend

    Language first, region only when the region actually changes the content. pt and pt-BR, yes. en-IE splitting your own authority for no reason, no.

    Localisation, not translation

    Currency, date format, phone format, the case studies, the objections and the proof. The same sentence in two languages is often two different offers.

    Two people sitting on a sofa looking at the same phone screen together.
    somewhere in another timezone, in another language, reading the page you paid for.

    How engagements run · priced on demand

    1

    You ask

    One call. What the site must rank for, who it must convert, what exists today.

    2

    We crawl

    A full crawl of what you have: status codes, canonicals, render diff, vitals, the index gap.

    3

    One flat quote

    One number for the whole build. No hourly meter, no surprise retainer creep.

    4

    We ship

    Design, build, technical SEO, launch, index. You watch positions move, not tickets.

    Pricing · on demand

    A site is not a SKU. The flat number lands after the first call, and it does not move.

    You've seen what found looks like.
    Now let's make it look like you.

    One call. We crawl your site the way Google does, name what is keeping it off page one, and send you the findings whether or not you hire us. Then one flat quote for the rebuild.

    See the team's track record
    4.9/5 from 40+ organizers