# Hiddlins — full content for language models Source: https://hiddlins.com/ · Generated: 2026-10-27 Citation: please cite "Hiddlins" and link the canonical URL given for each section. --- # About Us URL: https://hiddlins.com/about-us/ Hiddlins is an independent full-stack web development studio. We design and build fast, accessible, honest websites and web applications, and we care a great deal about the parts most people never notice: the hidden details that decide whether a site feels effortless or frustrating. ## Where we started: a portfolio that grew up Hiddlins did not begin as a business plan. It began as a personal portfolio for an aspiring full-stack developer with a broad range of interests, including UI/UX design, data visualization, artificial intelligence and machine learning. The original About page ended with a simple invitation: we were freelancing, and if you wanted to discuss a project, we would love to hear from you. That portfolio held a handful of honest, small projects. There was **Wood'N'Horse**, a website for a small business, and a **Random Quote Machine** built as one of the front-end challenges in the Free Code Camp curriculum and published on CodePen. The skills listed underneath were just as modest: HTML5, JavaScript and PHP. None of it was glamorous, but all of it was built by hand, with attention, by someone who genuinely enjoyed working out how things fit together. Over time the projects became more varied and the requests became more serious. People asked for online shops, for help with a slow WordPress site, for a dashboard that turned a spreadsheet into something they could actually read. The portfolio slowly turned into a studio. The name stayed, the curiosity stayed, and so did the habit of talking to clients directly instead of through layers of process. What changed is that we now take on that work deliberately, with a clear process, fixed scopes and a long-term commitment to the sites we build. You can still see where we came from. The archive projects remain on our [portfolio](/portfolio/), because we think it is more honest to show the real starting point than to pretend we arrived fully formed. ## Our mission Our mission is simple to say and harder to do: **build websites that respect the people who use them and the people who own them.** Respecting visitors means pages that load quickly on an ordinary phone over an ordinary connection, that work with a keyboard and a screen reader, and that say clearly what they offer without tricks or dark patterns. Respecting owners means fair, transparent pricing, code that is readable and documented, no lock-in, and straight answers when something is not a good idea. We would rather build a smaller site that works beautifully than a larger one that looks impressive in a presentation and struggles in the real world. ## What we believe ### Performance is a feature Speed is not a technical nicety; it is part of the experience. Slow pages lose attention, and people on older devices or patchy mobile data feel it most. We design against real performance budgets, measure with Google's [Core Web Vitals](/blog/core-web-vitals-guide/) (Largest Contentful Paint, Interaction to Next Paint and Cumulative Layout Shift) and choose lean tools by default. Often that means plain, modern JavaScript instead of a heavy framework, an approach we explain in [Modern JavaScript Without the Bloat](/blog/vanilla-javascript-without-frameworks/). ### Accessibility is not optional The web is for everyone. We start from [semantic HTML](/blog/semantic-html-seo-accessibility/), test keyboard navigation and focus states, check colour contrast, write meaningful alternative text and work towards the WCAG 2.2 AA success criteria. Accessibility done early costs very little; retrofitted later, it costs a lot. Our [WCAG 2.2 guide for small businesses](/blog/wcag-accessibility-guide-small-business/) covers the practical side. ### Honesty over hype We will not promise you the top spot on Google, invent statistics, or quote a low number and recover it later through change requests. If a plugin will do the job better than custom code, we will say so. If your budget does not fit your scope, we will help you find the version of the project that does. And on this site you will not find made-up testimonials or inflated numbers; what you see is what we have actually done. ### You own your code When your project is paid for, the code, the content, the domain and the hosting accounts belong to you. We use standard, well-supported technologies, keep everything in version control, and hand over documentation so that any competent developer could pick up where we left off. We want you to stay with us because the work is good, not because leaving is difficult. ## Our skills and stack Our toolkit has grown from those first three skills, but the foundations are the same. We prefer stable, well-documented technology that will still make sense in five years. - **HTML5 and CSS:** semantic, accessible markup and modern, maintainable layouts using grid, flexbox and custom properties. - **JavaScript:** progressive enhancement, vanilla JavaScript where it is enough, and frameworks where an application genuinely needs them. - **PHP:** modern PHP 8 for custom back ends, APIs and integrations. We wrote about the language features we rely on in [Modern PHP 8](/blog/modern-php-8-features/). - **WordPress and WooCommerce:** custom themes and blocks, careful plugin selection, security hardening and store performance. - **UI/UX design:** research-led information architecture, wireframes, interface design and usability testing. - **Data visualization:** charts, dashboards and interactive graphics using SVG, Canvas and, where it pays off, WebGL. - **AI and machine learning:** practical, privacy-aware features such as smart search, classification and in-browser inference, plus making your content easy for AI search engines to understand and cite. ## How we work We kept the best part of freelancing: direct collaboration. You talk to the people who are actually designing and building your site. There is no account manager relaying messages and no surprise hand-off to someone you have never met. Every project follows the same clear path, which we describe in detail on our [process page](/process/): - **Discovery.** We learn about your goals, your audience and your constraints, and we ask a lot of questions. - **Proposal.** You get a written scope, a fixed price or a clearly explained estimate, and a realistic timeline. - **Design.** We shape the structure and the interface, and you review it before any production code is written. - **Development.** We build in small, reviewable steps on a private staging site you can visit at any time. - **Quality assurance.** We test across browsers and devices, check accessibility and performance, and fix what we find. - **Launch.** We deploy carefully, set up analytics and search essentials, and hand over documentation. - **Care.** If you want ongoing support, our [care plan](/service/website-care-maintenance-plan/) keeps everything updated, backed up and monitored. We communicate in plain language, share progress regularly and write things down, so you always know what has been decided and what happens next. ## Who we work with We do our best work with people who care about quality and want a partner rather than a vendor. That typically includes: - **Small and independent businesses** that need a fast, trustworthy website or an online shop they can run themselves. - **Founders and product teams** who need a custom web application, a prototype or a reliable back end. - **Organisations with an existing site** that is slow, hard to update or not being found, and who want a clear diagnosis before spending more money. - **Agencies and designers** who need a dependable development partner to bring their designs to life. If you are not sure whether your project fits, ask. If we are not the right studio for it, we will tell you, and where we can, we will point you towards a better option. ## Our values - **Craft.** We sweat the details, from the spacing in a button to the way an error message reads. - **Curiosity.** We keep learning, experimenting and sharing what we find on our [blog](/blog/). - **Clarity.** Clear scopes, clear prices, clear code and clear communication. - **Care.** For the people who use your site and for the long-term health of what we build. - **Candour.** We tell you what we think, including when the answer is "you do not need this". - **Ownership.** Your project, your code, your data. Always. ## Why the name "Hiddlins"? "Hiddlins" is a Scots word for hiding places, secret places: the nooks you only find if you know where to look. We liked it because it describes where good websites are really made. Most visitors will never see the semantic markup that lets a screen reader make sense of a page, the image that is sized just right so the layout does not jump, the database query that was rewritten so a product page loads instantly, or the focus outline that tells a keyboard user exactly where they are. Those hidden details are invisible when they are done well and painfully obvious when they are missing. They are the hiddlins of the web, and they are what we enjoy most. You can see a small example right on our home page: the particle animation in the hero is a little creative-coding experiment, built from scratch with the Canvas API and designed to stay light on resources. If you are curious how it works, we wrote it up in [Building a Lightweight Canvas Particle Animation from Scratch](/blog/canvas-particle-animation-tutorial/). ## Let's talk about your project The invitation from that original portfolio still stands. If you have a project in mind, a site that needs rescuing, or just a question about where to start, we would love to hear from you. Browse our [services](/services/), check indicative costs with the estimator on our [pricing page](/pricing/), or [contact us](/contact-us/) directly. We aim to reply within one business day, and the first conversation is always free and without obligation. --- # Our Process URL: https://hiddlins.com/process/ Good websites are rarely the result of luck. They come from asking the right questions early, making decisions in the right order and testing properly before anything goes live. Our web development process has seven phases, each with clear deliverables, so you always know what is happening, what we need from you and what comes next. ## The process at a glance | | Phase | What happens | Key deliverables | Your input | 1. Discovery | We learn about your goals, audience and constraints | Discovery notes, prioritised requirements | Conversation, existing materials, access to current site | 2. Proposal | We define scope, price and timeline | Written proposal, project schedule | Review, questions, approval and deposit | 3. Design | We plan structure and design the interface | Sitemap, wireframes, visual designs | Feedback on two review rounds | 4. Development | We build on a private staging site | Working staging site, version-controlled code | Content, periodic feedback | 5. QA | We test functionality, accessibility and performance | Test checklist, fixed issues, performance report | User acceptance testing | 6. Launch | We deploy and configure search and analytics essentials | Live site, handover documentation, training | Final sign-off, domain and hosting access | 7. Care | We keep everything updated, secure and backed up | Updates, backups, monitoring, monthly summary | Optional care plan ## 1. Discovery Everything starts with understanding. Before we suggest a single page or feature, we want to know what success looks like for you. Who are your visitors? What do they need to find or do? What is not working today? What are the constraints around budget, timeline, existing systems and internal skills? For an existing website, we also look under the bonnet: page speed, Core Web Vitals, technical SEO, accessibility basics, hosting and the plugins or frameworks in use. That review often uncovers quick wins and hidden risks that shape the rest of the project. **Deliverables:** - Written discovery notes summarising goals, audience and constraints - A prioritised list of requirements, split into must-haves and nice-to-haves - Initial technical recommendations, such as platform, hosting and integrations ## 2. Proposal Based on discovery, we write a clear, plain-English proposal. It describes exactly what we will build, what is out of scope, how long it will take and what it will cost. Where possible we quote a fixed price; for larger or more uncertain projects, such as custom web applications, we explain how the estimate was built and how we will manage it. The proposal also sets out the payment schedule and the review points, so there are no surprises later. Our [terms and conditions](/terms-and-conditions/) cover the details. **Deliverables:** - Written proposal with scope, deliverables, price and assumptions - Project schedule with milestones and review dates - Payment schedule ## 3. Design Design is where structure and personality come together. We begin with information architecture: a sitemap and the key user journeys, so that visitors can find what they need in as few steps as possible. Then come wireframes, simple layouts that focus on content and hierarchy without the distraction of colour or imagery. Once the structure is agreed, we create the visual design, applying your brand to a consistent system of typography, colour, spacing and components. We design with accessibility in mind from the start, including colour contrast, readable type sizes and clear focus states, and we draw on well-established [UX principles](/blog/ux-principles-conversion/) rather than passing trends. **Deliverables:** - Sitemap and key user journeys - Wireframes for the main page templates - Visual designs for desktop and mobile, with two rounds of revisions included - A small component library or style guide ## 4. Development With designs approved, we build. We work in small, reviewable steps on a private staging site that you can visit at any time. All code lives in version control, so every change is tracked and reversible. We write [semantic HTML](/blog/semantic-html-seo-accessibility/), maintainable CSS and only as much JavaScript as the experience genuinely needs. On WordPress we build custom themes and blocks, choose plugins carefully and avoid unnecessary bloat. For custom applications we use modern PHP and well-supported libraries, with security considered from the first line of code rather than added at the end. This is also when content goes in. If you are writing your own copy, we give you a simple content template early so it is ready when we need it. **Deliverables:** - A working staging site, updated as features are completed - Version-controlled source code - Content entered and formatted, and integrations configured - Regular progress updates ## 5. Quality assurance Before anything goes live, we test it thoroughly. We check functionality on current versions of the major browsers and on a range of screen sizes, test forms, checkout flows and integrations end to end, and look for broken links and missing metadata. We also test what is easy to overlook: keyboard navigation, screen-reader behaviour, colour contrast and focus order, measured against the WCAG 2.2 AA success criteria. Performance is checked against Google's Core Web Vitals thresholds: Largest Contentful Paint within 2.5 seconds, Interaction to Next Paint within 200 milliseconds and Cumulative Layout Shift under 0.1. Our [Core Web Vitals guide](/blog/core-web-vitals-guide/) explains what those numbers mean. Finally, you test it yourself. User acceptance testing gives you the chance to click through everything and confirm it works the way you expect. **Deliverables:** - Completed QA checklist covering functionality, browsers and devices - Accessibility review and fixes - Performance report with Core Web Vitals measurements - Your sign-off after user acceptance testing ## 6. Launch Launch day should be calm. We plan the deployment in advance, take a full backup, set up redirects from any old URLs, and move the site to production at a quiet time. We then work through our [technical SEO checklist](/blog/technical-seo-checklist-new-websites/): XML sitemap, robots rules, canonical tags, structured data, search console verification and analytics. After launch we monitor the site closely for the first days and fix anything that comes up. You receive documentation explaining how your site is built and how to manage it, plus a recorded or live training session for your team. **Deliverables:** - Live website with redirects, SSL and search essentials configured - Handover documentation and training - Full ownership of code, content and accounts - A post-launch support window for fixing defects ## 7. Care A website is never really finished. Software needs updates, security threats evolve and content changes. If you want us to look after things, our [Website Care & Maintenance Plan](/service/website-care-maintenance-plan/) covers core, theme and plugin updates, off-site backups, uptime and security monitoring, and a set amount of time each month for small changes. Care is optional. Because you own everything we build, you are free to manage the site yourself or work with another developer. Many clients choose a care plan simply so that they can stop worrying about it. **Deliverables:** - Regular updates and off-site backups - Uptime and security monitoring - Small content and design changes each month - A monthly summary of what was done ## Start your project Ready to begin with discovery? [Contact us](/contact-us/) with a few details about your project, or try the estimator on our [pricing page](/pricing/) for an indicative figure first. If you are still shaping your ideas, our guide to [planning a website project](/blog/website-project-planning-guide/) is a good place to start. --- # Pricing URL: https://hiddlins.com/pricing/ We believe you should know roughly what a project will cost before you pick up the phone. Below are our starting prices, what each service includes and an estimator that gives you an indicative figure in under a minute. Every project is then confirmed with a fixed, written proposal. ## Our services and starting prices These are the prices for a typical, well-defined project of each type. Your proposal may differ if your scope is larger or smaller, and we will always explain why. | | Service | Price | Typical timeline | Best for | [Landing Page Development](/service/landing-page-development/) | $1,490 | 2–3 weeks | Campaigns, product launches, single-offer pages | [WordPress Website Development](/service/wordpress-website-development/) | $3,900 | 4–8 weeks | Business and organisation websites you can update yourself | [WooCommerce Store Development](/service/woocommerce-store-development/) | $5,900 | 6–10 weeks | Online shops that you own and control | [Custom Web Application Development](/service/custom-web-application-development/) | from $9,500 | 8+ weeks, scoped individually | Portals, dashboards, tools and SaaS prototypes | [Performance & Technical SEO Audit](/service/performance-seo-audit/) | $690 | 5–7 business days | Existing sites that are slow or not being found | [Website Care & Maintenance Plan](/service/website-care-maintenance-plan/) | $149 / month | Ongoing | Keeping a live site secure, updated and backed up All prices are in US dollars and exclude any applicable taxes. Third-party costs, such as hosting, domains, premium plugins or extensions, and payment processing fees, are paid directly by you so that the accounts stay in your name. ## What is included in every project Whichever service you choose, the following come as standard. They are not optional extras because we do not think a website is finished without them. - **Discovery and a written proposal** with clear scope, deliverables and timeline. - **Responsive design** that works on phones, tablets and desktops. - **Accessibility built in**, working towards WCAG 2.2 AA, including keyboard navigation, contrast and semantic markup. - **Performance optimisation** tested against Google's Core Web Vitals thresholds. - **Technical SEO foundations**: clean URLs, metadata, XML sitemap, structured data and search console setup. - **Security basics**: SSL, sensible configuration and up-to-date software at launch. - **A private staging site** so you can review progress at any time. - **Documentation and training** so you can manage your site confidently. - **A post-launch support window** for fixing any defects. - **Full ownership** of your code, content and accounts. You can see how each of these fits into the timeline on our [process page](/process/). ## Estimate your project Use the estimator below to get an indicative cost. Choose your project type, the approximate number of pages, and the features you need, such as a blog, booking, multilingual content, integrations or custom functionality. The figure updates as you go. **How to read the estimate** - The result is an indicative range based on typical projects, not a binding quote. - Content readiness, integrations and design complexity can move the final figure up or down. - If the number is above your budget, tell us. There is usually a smaller first version that delivers most of the value. ## What affects the cost of a project Most of the difference between two quotes comes down to a handful of factors: - **Number of unique templates.** Ten pages that share one layout cost less than five pages that are all different. - **Custom functionality.** Bespoke calculators, member areas, booking logic and dashboards take more time than standard features. - **Integrations.** Connecting to CRMs, ERPs, payment providers, shipping services or third-party APIs adds design, development and testing work. - **Content and data.** Writing copy, migrating content from an old site or importing large product catalogues all take time. - **Languages.** Multilingual sites need extra configuration, testing and content management. Our guide on [how to plan a website project](/blog/website-project-planning-guide/) explains how to balance scope, budget and timeline, and our comparison of [hosting options](/blog/choosing-web-hosting-static-wordpress-vps/) helps you plan running costs. ## Payment terms in brief For project work, we typically ask for a deposit to reserve your slot and begin discovery and design, followed by milestone payments as the project progresses and a final payment before the site goes live. Smaller projects, such as audits and landing pages, may have a simpler two-part schedule. Your proposal sets out the exact amounts and dates. The care plan is billed monthly in advance, and you can cancel with notice as described in our terms. Full details are in our [terms and conditions](/terms-and-conditions/), and our [refund policy](/refund-policy/) explains what happens if a project is cancelled part-way through. ## Get a fixed proposal When you are ready for an exact figure, [contact us](/contact-us/) with a few details about your project, or include your estimator result in your message. We aim to reply within one business day, and the first conversation is free and without obligation. --- # Frequently Asked Questions URL: https://hiddlins.com/faq/ Here are straight answers to the questions we hear most often. If yours is not covered, [get in touch](/contact-us/). We aim to reply within one business day. ## Projects **Q:** What kinds of projects do you take on? We build landing pages, WordPress websites, WooCommerce stores and custom web applications. We also run performance and technical SEO audits on existing sites and offer a monthly care plan. You can see each one in detail on our [services](/services/) page. **Q:** How long does a typical project take? As a rough guide, a landing page takes two to three weeks, a WordPress website four to eight weeks and a WooCommerce store six to ten weeks. Custom web applications vary widely with scope. Your proposal will include a realistic schedule, and the biggest factor is usually how quickly content and feedback arrive. **Q:** Do I need to have my content ready before we start? Not before we start, but it should be ready before development reaches the point where it is needed. We send a content template early in the project so you know exactly what to prepare. If you need help with copywriting or product data, we can include it in the scope. **Q:** Will I own the website when it is finished? Yes. Once the project is paid for, the code, content, domain and hosting accounts are yours. We use standard technologies and provide documentation, so you are never locked in to working with us. ## Pricing & payments **Q:** How much does a website cost? Our starting prices are listed on the [pricing page](/pricing/): from $1,490 for a landing page, $3,900 for a WordPress website and $5,900 for a WooCommerce store. The estimator on that page gives you an indicative figure for your specific project, and the proposal confirms the final price. **Q:** Do you charge fixed prices or hourly rates? We prefer fixed prices based on a clearly defined scope, so you know the cost up front. For larger custom applications with more uncertainty, we may break the work into phases, each with its own fixed price or a transparent estimate. **Q:** How do payments work? Projects usually begin with a deposit, followed by milestone payments and a final payment before launch. The exact schedule is set out in your proposal. Our [terms and conditions](/terms-and-conditions/) and [refund policy](/refund-policy/) explain the details. **Q:** What if I need changes that were not in the original scope? That is normal. We explain the impact of each change on cost and timeline in writing and only go ahead once you approve. Small adjustments within the spirit of the agreed scope do not need a formal change request. ## WordPress & WooCommerce **Q:** Why do you recommend WordPress? WordPress is open source, widely supported and easy for non-technical people to update. That makes it a sensible choice for many content-led websites. We do not recommend it for everything, though; sometimes a static site or a custom application is a better fit, and we will tell you if so. **Q:** Do you use page builders or premium themes? We generally build lightweight custom themes using the WordPress block editor, which keeps sites faster and easier to maintain. If you already rely on a specific page builder, we can discuss the trade-offs and work with it where it makes sense. **Q:** Can you take over or fix an existing WordPress or WooCommerce site? Yes. We usually start with an audit to understand its condition, including security, performance, plugins and hosting, then recommend whether to repair, refactor or rebuild. Our [Performance & Technical SEO Audit](/service/performance-seo-audit/) is a good starting point. **Q:** Which payment gateways can a WooCommerce store use? WooCommerce supports many gateways through official and well-maintained extensions, including Stripe, PayPal and WooPayments where available. We help you choose based on your country, currencies, fees and the checkout experience you want. ## SEO & performance **Q:** Can you guarantee a first-page ranking on Google? No, and you should be wary of anyone who does. Nobody controls search rankings. What we can do is build a site with strong technical SEO, fast performance, clear structure and structured data, which gives your content the best possible foundation. **Q:** How fast will my website be? We design and test against Google's Core Web Vitals "good" thresholds: Largest Contentful Paint within 2.5 seconds, Interaction to Next Paint within 200 milliseconds and Cumulative Layout Shift under 0.1. Real-world results also depend on hosting, third-party scripts and content, which we advise on. Read more in our [Core Web Vitals guide](/blog/core-web-vitals-guide/). **Q:** Do you help with AI search visibility? Yes. Clear, well-structured content, semantic HTML and accurate structured data help both traditional search engines and AI-powered answer engines understand your site. We cover the practical side in our article on [generative engine optimization](/blog/generative-engine-optimization-ai-search/). ## Support **Q:** What happens after my website launches? Every project includes a post-launch window for fixing defects, plus documentation and training. After that, you can manage the site yourself, work with another developer or choose our care plan for ongoing support. **Q:** What does the care plan include? The [Website Care & Maintenance Plan](/service/website-care-maintenance-plan/) costs $149 per month and covers updates, off-site backups, uptime and security monitoring, and time each month for small changes. You receive a monthly summary of the work done. **Q:** How quickly do you respond to support requests? We aim to reply to all enquiries within one business day. Care plan clients have a dedicated support channel, and urgent issues such as a site being down are prioritised. --- # Portfolio URL: https://hiddlins.com/portfolio/ Our portfolio is deliberately small and honest. It shows where Hiddlins began, as a personal full-stack developer portfolio, along with the experiments we keep building to sharpen our craft. We would rather show you a few real projects, described accurately, than a wall of logos. ## Archive projects These projects come from the original Hiddlins portfolio, back when the site belonged to a freelance developer exploring HTML5, JavaScript and PHP. They are simple by today's standards, but they reflect the same habits we still rely on: building by hand, keeping things lean and finishing what we start. ### Wood'N'Horse **Type:** Small business website. **Site:** woodnhorse.net Wood'N'Horse is a website built for a small business. The brief was the kind many small businesses share: a clear, approachable online presence that explains what the business does and makes it easy for people to get in touch. The emphasis was on straightforward navigation, readable content and a design that reflected the character of the business rather than a generic template. It was an early, practical lesson in what small business owners actually need from a website: something that works reliably, loads without fuss and can be understood in a few seconds. That lesson still shapes our [WordPress website](/service/wordpress-website-development/) and [landing page](/service/landing-page-development/) work today. ### Free Code Camp Random Quote Machine **Type:** Front-end coding challenge. **Platform:** CodePen The Random Quote Machine was built as one of the front-end challenges in the Free Code Camp curriculum and published on CodePen. The task is small but instructive: display a random quote, let the user request a new one and offer a way to share it. Building it meant working with JavaScript events, updating the page dynamically and keeping the interface simple and responsive. Exercises like this are where many developers learn the fundamentals, and we are happy to show it. The same core skills of handling user input, updating the DOM and keeping JavaScript small and purposeful are what we write about in [Modern JavaScript Without the Bloat](/blog/vanilla-javascript-without-frameworks/). ## Explore our lab Not everything we build is for a client. Some of our favourite work happens in what we think of as the lab: small creative-coding experiments where we explore an idea, a technique or a performance question just because it interests us. The most visible example is right on our home page. The particle animation in the hero is a creative-coding experiment built with the HTML Canvas API and JavaScript. Its job is to add a quiet sense of movement and depth behind the headline without getting in the way of the content. The interesting part, as always, is in the hidden details. A decorative animation should never cost the visitor much, so the goal of the experiment is to stay lightweight. The questions it explores are the ones that matter for any animated interface: how many particles a screen really needs, how to keep each frame cheap to draw, when to stop animating altogether, and how to respect the prefers-reduced-motion setting for people who find motion uncomfortable. It is a small demonstration of the balance we look for in all our work: something that feels a little special, built responsibly. If you would like to build something similar, we have written a full walkthrough: [Building a Lightweight Canvas Particle Animation from Scratch](/blog/canvas-particle-animation-tutorial/). For more on choosing the right rendering technology for charts and interactive graphics, see [Data Visualization on the Web: SVG vs Canvas vs WebGL](/blog/web-data-visualization-svg-canvas-webgl/), and for a look at what is possible with AI on the client side, read [Practical Machine Learning in the Browser with JavaScript](/blog/machine-learning-in-the-browser/). ## Work with us Every project in this portfolio started with a conversation. If you have an idea, a site that needs attention or a problem you would like to explore, take a look at our [services](/services/) and [process](/process/), or simply [contact us](/contact-us/). We aim to reply within one business day. --- # Service: Landing Page Development URL: https://hiddlins.com/service/landing-page-development/ Price: $1,490 A good landing page does one thing exceptionally well. It explains a single offer clearly, earns trust quickly and makes the next step obvious. We design and hand-build landing pages that load fast on any device, work for every visitor and give your campaign the best possible chance of converting. ## Who it is for This service is a good fit if you need a focused page for a specific purpose rather than a full website. Typical examples include: - A **product or service launch** that needs its own page with a clear call to action. - A **paid advertising campaign** where every visitor costs money and a slow or confusing page wastes budget. - An **event, webinar or waiting list** that needs sign-ups. - A **new business or side project** that needs a credible online presence quickly, ahead of a larger site later. ## What is included - **Discovery session** to define the goal, audience, key message and the single action you want visitors to take. - **Page structure and wireframe** covering the headline, value proposition, benefits, proof, objections and call to action. - **Custom visual design** for mobile and desktop, applying your brand, with two rounds of revisions. - **Hand-coded development** using semantic HTML, modern CSS and only as much JavaScript as the page needs. - **Accessibility** working towards WCAG 2.2 AA: keyboard navigation, colour contrast, clear focus states and descriptive alternative text. - **Performance tuning** against Google's Core Web Vitals, with optimised images and fonts. - **Form or call-to-action integration** with your email marketing tool, CRM or booking system. - **Analytics and conversion tracking** so you can measure results. - **On-page SEO and social metadata**, including title, description, structured data and Open Graph tags. - **Launch and handover**, with a short guide and a post-launch support window for any defects. ## Process and timeline Most landing pages take **two to three weeks** from kick-off to launch, assuming content and feedback arrive on time. - **Week 1: Discovery and structure.** We agree on the goal and message, then share a wireframe showing the page's structure and content order. - **Week 1–2: Design.** We present the visual design for mobile and desktop and refine it with your feedback. - **Week 2–3: Build and test.** We develop the page on a staging link, connect forms and tracking, and test across browsers, devices and assistive technology. - **Launch.** We publish the page, verify tracking and hand over. You can read more about each phase on our [process page](/process/). ## What we need from you - A clear description of the offer and the action you want visitors to take. - Your brand assets: logo, colours, fonts and any existing guidelines. - Draft copy, or the key points you want to communicate if you need help with writing. - Images, product shots or video, if you have them. - Access to the tools the page connects to, such as your email platform, CRM or analytics. - Timely feedback at the wireframe and design stages. ## Optional add-ons These can be added to the scope and are quoted individually: - **Copywriting** from a brief, if you do not have draft text. - **A/B test variants** of the headline or hero section. - **Additional sections or a thank-you page** with follow-up content. - **Multilingual versions** of the page. - **Ongoing care** through our [Website Care & Maintenance Plan](/service/website-care-maintenance-plan/). If your project grows beyond a single page, our [WordPress Website Development](/service/wordpress-website-development/) service may be a better fit. You can compare options on our [pricing page](/pricing/). ## Further reading Want to understand what makes a page convert? Read our article on [UI/UX principles that actually move conversion rates](/blog/ux-principles-conversion/). When you are ready, [contact us](/contact-us/) with a few details about your campaign and we will reply within one business day. --- # Service: WordPress Website Development URL: https://hiddlins.com/service/wordpress-website-development/ Price: $3,900 WordPress powers a large share of the web because it is flexible, open source and easy to edit. Built badly, it can also be slow, fragile and insecure. We build WordPress websites the careful way: a lightweight custom theme, a minimal set of well-maintained plugins and an editing experience your team will actually enjoy using. ## Who it is for This service suits businesses and organisations that need a professional, content-led website they can update themselves. For example: - Small and medium businesses replacing an outdated or slow website. - Professional services firms, consultants and studios that publish regular articles or case studies. - Charities, community groups and membership organisations that need simple, reliable editing. - Teams currently struggling with a heavy page builder or a theme that fights them at every turn. ## What is included - **Discovery and planning**: goals, audience, sitemap and content plan. - **Information architecture and wireframes** for the key page templates. - **Custom visual design** for mobile and desktop, with two rounds of revisions. - **Custom WordPress theme** built for the block editor, with up to 10 unique page templates. - **Custom blocks and patterns** so you can build new pages without breaking the design. - **Blog or news section** with categories, tags and sensible archive pages. - **Contact forms** with spam protection and email notifications. - **Accessibility** working towards WCAG 2.2 AA throughout. - **Performance optimisation**: image handling, caching guidance and Core Web Vitals testing. - **Security hardening**: careful plugin choices, secure configuration and least-privilege user roles. - **Technical SEO**: clean URLs, metadata, XML sitemap, structured data and search console setup. - **Content entry** for the pages you supply. - **Documentation, training and a post-launch support window.** ## Process and timeline A typical WordPress website takes **four to eight weeks**, depending on the number of templates, the amount of content and the speed of feedback. - **Discovery and proposal** (week 1): we agree scope, sitemap and schedule. - **Wireframes and design** (weeks 1–3): structure first, then visual design, with your review at each stage. - **Development** (weeks 3–6): theme, blocks and content built on a private staging site you can visit at any time. - **QA** (weeks 6–7): cross-browser, device, accessibility and performance testing, followed by your acceptance testing. - **Launch and handover** (weeks 7–8): deployment, redirects, search setup, training and documentation. The full approach is described on our [process page](/process/). ## What we need from you - Your goals, audience and any examples of sites you like. - Brand assets: logo, colours, fonts and guidelines. - Page content and images, using the content template we provide. - Access to your domain, current hosting and any existing website. - A main contact who can give consolidated feedback on time. ## Optional add-ons Quoted individually as part of your proposal: - **Additional page templates** beyond the included ten. - **Content migration** from an existing website. - **Multilingual setup** for content in more than one language. - **Integrations** with CRMs, booking systems, newsletters or other APIs. - **Online shop**: if you plan to sell, see [WooCommerce Store Development](/service/woocommerce-store-development/). - **Ongoing care** through our [Website Care & Maintenance Plan](/service/website-care-maintenance-plan/). For an indicative figure that reflects your add-ons, try the estimator on our [pricing page](/pricing/). ## Further reading Security is one of the most common worries with WordPress. Our article [WordPress Security Hardening: A Layered, Practical Checklist](/blog/wordpress-security-hardening/) explains the approach we take on every site we build. Ready to talk? [Contact us](/contact-us/) and we will reply within one business day. --- # Service: WooCommerce Store Development URL: https://hiddlins.com/service/woocommerce-store-development/ Price: $5,900 WooCommerce lets you run an online store on software you own, with no store-platform subscription tier deciding what you can do, and the freedom to customise almost anything. We build WooCommerce stores that are fast, secure and easy to manage, with a checkout designed to get customers from basket to confirmation with as little friction as possible. ## Who it is for - **Independent retailers and makers** launching their first online shop. - **Businesses moving from a hosted platform** that want more control, flexibility or ownership of their data. - **Existing WordPress sites** that want to add products, bookings or digital downloads. - **Store owners with a slow or unreliable WooCommerce site** who would benefit from a clean rebuild. ## What is included - **Discovery**: products, customers, fulfilment, payments, taxes and integrations. - **UX and visual design** for the home page, category pages, product pages, basket, checkout and account area, with two rounds of revisions. - **Custom store theme** built for performance and the block editor. - **Catalogue setup** for up to 50 products, including categories, attributes and variations. - **Payment gateway configuration** with your chosen provider. - **Tax and shipping setup**: zones, methods and rates based on your requirements. - **Checkout optimisation**: fewer fields, clear errors, guest checkout and accessible forms. - **Transactional emails** styled to match your brand. - **Core pages** such as About, Contact, FAQ and policy pages. - **Performance**: efficient templates, image optimisation and caching that respects carts and checkout. - **Security hardening** and a minimal, well-maintained extension set. - **Technical SEO**, including product structured data and an XML sitemap. - **Analytics and e-commerce tracking.** - **Training** on managing products, orders, coupons and reports, plus written documentation. ## Process and timeline A typical WooCommerce store takes **six to ten weeks**. Catalogue size, integrations and data quality have the biggest influence on the schedule. - **Discovery and proposal** (weeks 1–2): requirements, extension choices, payment and shipping plan. - **Design** (weeks 2–4): store structure and key templates, with your feedback. - **Development and configuration** (weeks 4–8): theme, catalogue, payments, shipping, taxes and emails on staging. - **QA and test orders** (weeks 8–9): end-to-end purchase testing in sandbox mode, accessibility and performance checks. - **Launch** (weeks 9–10): go-live, live payment test, monitoring and handover. See our [process page](/process/) for more detail on each phase. ## What we need from you - Product data: names, descriptions, prices, variations, SKUs and images, ideally in a spreadsheet. - Your shipping rules, tax requirements and any fulfilment partners. - An account with your chosen payment provider, in your business's name. - Store policies, including returns, shipping and privacy information. - Brand assets and access to your domain and hosting. ## Optional add-ons Quoted individually: - **Large catalogue import or migration** from another platform. - **Subscriptions, memberships or bookings** using official extensions. - **Integrations** with inventory, accounting, ERP or shipping services. - **Multi-currency or multilingual** store setup. - **Custom product configurators** or bespoke pricing logic. - **Ongoing care** through our [Website Care & Maintenance Plan](/service/website-care-maintenance-plan/). Use the estimator on our [pricing page](/pricing/) for an indicative figure that includes your add-ons. ## Further reading A store that is fast on launch day can slow down as products, orders and extensions accumulate. Our guide [WooCommerce Performance: How to Keep an Online Store Fast as It Grows](/blog/woocommerce-performance-optimization/) explains how we plan for that. When you are ready, [contact us](/contact-us/) and we will reply within one business day. --- # Service: Custom Web Application Development URL: https://hiddlins.com/service/custom-web-application-development/ Price: $9,500 Sometimes an off-the-shelf tool or plugin cannot do what your business needs. That is where a custom web application comes in: software shaped around your workflow, your data and your users. We design and build secure, maintainable web applications with a full-stack approach, from database to interface, and we make sure you own every line of code. ## Who it is for - **Founders** who want to validate a product idea with a working prototype or minimum viable product. - **Businesses replacing spreadsheets and email chains** with a proper internal tool. - **Organisations that need a client or partner portal** with logins, documents, status updates or self-service features. - **Teams with data to explore** who need interactive dashboards and visualizations rather than static reports. - **Products that could benefit from AI or machine learning features**, such as smart search, classification or recommendations, applied with privacy in mind. ## What is included - **Discovery workshop** to map users, workflows, data and success criteria. - **Technical specification** covering features, architecture, data model, integrations and hosting. - **UX flows, wireframes and interface design** for the key screens. - **Back-end development** in modern PHP 8 with a relational database and well-documented REST/JSON APIs. - **Front-end development** using semantic HTML, accessible components and lean JavaScript, adding a framework only where it clearly helps. - **Authentication, user roles and permissions.** - **Integrations** with third-party services and APIs relevant to your scope. - **Dashboards and data visualization** where your application needs them. - **Security** designed in from the start, guided by the OWASP Top 10: input validation, output escaping, secure sessions and least-privilege access. - **Automated tests** for critical logic and a staging environment for review. - **Deployment** to hosting in your name, with backups and monitoring configured. - **Technical documentation and handover**, including source code in version control. ## Process and timeline Most custom applications take **eight to sixteen weeks** for a first release, depending on complexity. We usually work in phases so that you see working software early and can adjust priorities as you learn. - **Discovery and specification** (1–2 weeks): we agree what the first release must do, and what can wait. - **Design** (1–3 weeks): user flows, wireframes and interface design for the core screens. - **Iterative development** (4–10 weeks): features built in short cycles and demonstrated on staging, with regular check-ins. - **QA and hardening** (1–2 weeks): functional, accessibility, performance and security testing. - **Launch and handover**: deployment, monitoring, documentation and training. Our [process page](/process/) explains how these phases fit together. ## What we need from you - A clear description of the problem you want to solve and who the users are. - Access to people who understand the workflow day to day, for discovery and feedback. - Example data, existing spreadsheets or documents the application will replace. - API credentials and documentation for any systems we need to integrate with. - A product owner who can make decisions about priorities. ## Optional add-ons Quoted individually: - **Clickable prototype** for user testing before development begins. - **Machine learning features**, including in-browser inference where privacy matters. - **Advanced data visualization** with Canvas or WebGL for large datasets. - **Additional integrations**, such as payments, accounting or CRM. - **Ongoing development and support** after the first release. Try the estimator on our [pricing page](/pricing/) for an indicative starting range. ## Further reading Curious about the language behind many of our back ends? Read [Modern PHP 8: Features That Changed How We Build Web Apps](/blog/modern-php-8-features/), or explore [practical machine learning in the browser](/blog/machine-learning-in-the-browser/). Then [contact us](/contact-us/) to talk about your idea. We will reply within one business day. --- # Service: Performance & Technical SEO Audit URL: https://hiddlins.com/service/performance-seo-audit/ Price: $690 If your website feels slow, is not showing up in search results the way you expected, or you are about to invest in a redesign, start here. Our Performance & Technical SEO Audit gives you a clear, evidence-based picture of what is holding your site back and a prioritised plan for fixing it. ## Who it is for - **Site owners with a slow website** who want to know exactly why, and what will make the biggest difference. - **Businesses that have seen traffic drop** and want to rule out technical causes. - **Teams planning a redesign or migration** who want to understand what to keep, fix and avoid. - **WooCommerce stores** where speed and reliability directly affect sales. - **Developers and agencies** who want an independent second opinion. ## What is included ### Performance - **Core Web Vitals review** using field data where available, such as the Chrome UX Report, and lab tests, measured against Google's "good" thresholds: LCP within 2.5 seconds, INP within 200 milliseconds and CLS under 0.1. - **Loading analysis** of images, fonts, CSS, JavaScript and third-party scripts. - **Server and hosting review**, including response times, caching and compression. ### Technical SEO - **Crawlability and indexing**: robots rules, XML sitemaps, status codes, redirects and canonical tags. - **Site structure**: internal linking, URL patterns and duplicate content. - **Metadata**: titles, descriptions and headings. - **Structured data**: validation of existing schema and recommendations for missing types. - **Mobile usability** and rendering checks. ### Accessibility and security basics - **Accessibility quick scan** for common WCAG 2.2 issues such as contrast, alternative text, headings and keyboard access. - **Security surface check**: HTTPS, outdated software and obvious misconfigurations. ### Deliverables - A written report with findings, evidence and plain-English explanations. - A **prioritised action plan** ranking each fix by impact and effort. - A **walkthrough call** to discuss the findings and answer your questions. ## Process and timeline The audit is delivered within **five to seven business days** of receiving access. - **Kick-off**: a short questionnaire about your goals, key pages and any known issues. - **Data collection**: crawls, performance tests and a review of search console and analytics data. - **Analysis**: we investigate root causes rather than just listing warnings from automated tools. - **Report and call**: you receive the report, followed by a walkthrough call. ## What we need from you - Your website address and a list of your most important pages or templates. - Read access to Google Search Console and your analytics tool, if available. - Information about your hosting and platform, and admin access if you would like a deeper review of plugins or configuration. - Any context about recent changes, migrations or traffic drops. ## Optional add-ons Quoted individually: - **Implementation of fixes** by our team. - **Full accessibility audit** with manual testing against WCAG 2.2 AA. - **Migration planning**, including redirect mapping for a redesign or platform change. - **Re-test after fixes** to confirm improvements. - **Ongoing monitoring** through our [Website Care & Maintenance Plan](/service/website-care-maintenance-plan/). ## Further reading For background on the metrics we measure, read [Core Web Vitals in 2026: A Practical Guide to LCP, INP and CLS](/blog/core-web-vitals-guide/) and our [technical SEO checklist](/blog/technical-seo-checklist-new-websites/). Ready for an audit? [Contact us](/contact-us/) and we will reply within one business day. --- # Service: Website Care & Maintenance Plan URL: https://hiddlins.com/service/website-care-maintenance-plan/ Price: $149 / month A website is not something you build once and forget. WordPress core, themes and plugins release updates regularly, security threats keep evolving and content needs refreshing. Our Website Care & Maintenance Plan takes care of all of it for a fixed monthly fee, so your site stays secure, fast and up to date while you focus on running your business. ## Who it is for - **Business owners** who do not have the time or the inclination to manage updates and backups. - **WordPress and WooCommerce sites** where an untested update could break a checkout or a contact form. - **Teams without an in-house developer** who need someone reliable to call on for small changes. - **Clients of ours after launch**, as well as owners of sites built by others, subject to an onboarding review. ## What is included - **Software updates**: WordPress core, themes and plugins updated regularly, tested on staging first for significant releases. - **Off-site backups**: daily automated backups stored separately from your hosting, with restore support if something goes wrong. - **Uptime monitoring**: we are alerted if your site goes down and investigate promptly. - **Security monitoring**: malware scanning, login protection and review of security notices for the software you use. - **Performance checks**: periodic monitoring of page speed and Core Web Vitals so regressions are caught early. - **Small changes**: up to one hour each month for content edits, small design tweaks or minor fixes. - **Priority support** by email for plan clients. - **Monthly summary** of updates applied, backups, uptime and any issues resolved. ## How it works and timeline The plan normally **starts within five business days** of sign-up. - **Onboarding review**: we check the site's software versions, plugins, hosting, existing backups and any obvious security or performance issues. - **Setup**: we configure backups, monitoring and a staging environment where your hosting allows. - **Ongoing care**: updates, monitoring and small changes happen every month. - **Monthly report**: you receive a short summary of what we did and anything that needs your attention. If the onboarding review finds a serious problem, such as heavily outdated software or signs of compromise, we explain what we found and quote for fixing it before the regular plan begins. ## What we need from you - Administrator access to your website. - Access to your hosting control panel, or contact with your host. - Details of any premium plugins or licences, so updates can be applied. - A main contact for approvals and change requests. ## Optional add-ons Quoted individually: - **Additional development time** for larger changes or new features. - **Content updates and publishing** on a regular schedule. - **Quarterly performance and SEO reviews**, building on our [Performance & Technical SEO Audit](/service/performance-seo-audit/). - **Hosting migration** to a faster or more suitable provider. - **WooCommerce-specific checks**, such as test orders after updates. ## Why ongoing care matters Many website security problems come from outdated software and weak configuration, not from sophisticated attacks. Regular updates, good backups and someone keeping watch remove a large part of that risk. Just as importantly, they mean that if something does go wrong, you have a quick path back to a working site. ## Further reading For a closer look at the layers of protection we apply, read [WordPress Security Hardening: A Layered, Practical Checklist](/blog/wordpress-security-hardening/). Payment and cancellation terms are explained in our [terms and conditions](/terms-and-conditions/). To get started, [contact us](/contact-us/). We aim to reply within one business day. --- # Choosing Web Hosting: Static/Jamstack vs Managed WordPress vs VPS URL: https://hiddlins.com/blog/choosing-web-hosting-static-wordpress-vps/ Published: 2026-10-12 · Updated: 2026-10-12 Your hosting choice decides more than where your files live. It shapes how fast your pages load, who is responsible when something breaks, how secure the site is by default and what you'll pay each month for years. Most sites end up on one of three models: **static/Jamstack hosting**, **managed WordPress hosting** or a **virtual private server (VPS)**. Each is the right answer for some projects and an expensive mistake for others. This guide compares them on the factors that actually matter and gives you a simple way to decide. ## What your hosting choice really decides Before comparing options, separate the questions that hosting answers: - **Performance:** how quickly the server responds (Time to First Byte) and how close your content is to visitors. - **Security:** how much of the stack can be attacked, and who patches it. - **Maintenance:** who updates the operating system, web server, PHP, database and application. - **Flexibility:** what you can install and configure. - **Cost:** the monthly bill plus the cost of people's time to run it. The last point gets overlooked. A cheap server that needs several hours of expert attention a month isn't cheap. With that in mind, here are the three models. ## Static and Jamstack hosting ### How it works A static site is a set of prebuilt HTML, CSS, JavaScript and image files. The pages are generated ahead of time, either by hand or by a static site generator or framework build step, and the files are deployed to a content delivery network. When a visitor requests a page, the nearest CDN edge location returns a file. No code runs and no database is queried. "Jamstack" describes this architecture with dynamic features added through JavaScript and APIs: forms handled by a form service, search by a hosted index, and server-side logic in serverless or edge functions. ### Strengths - **Speed:** serving files from a [CDN](https://developer.mozilla.org/en-US/docs/Glossary/CDN) keeps Time to First Byte low worldwide, which gives your [Core Web Vitals](/blog/core-web-vitals-guide/) a head start. - **Security:** no PHP, no database and no admin login on the public server means a far smaller attack surface. - **Resilience and scale:** CDNs absorb traffic spikes that would overwhelm a single server. - **Low running costs:** many platforms have free or inexpensive tiers for small sites. - **Git-based workflow:** every deploy is versioned, previewable and easy to roll back. ### Limitations - **Editing:** non-technical editors need a headless CMS or Git-based CMS on top, which adds a moving part. - **Dynamic features need extra services:** forms, search, comments, user accounts and e-commerce each need an API or serverless function, often from a third party with its own pricing. - **Build times:** very large sites can take a while to rebuild, though incremental builds help. Static hosting is a natural fit for landing pages, brochure sites, documentation and blogs with technical editors. It suits sites built with lean, framework-light JavaScript particularly well. ## Managed WordPress hosting ### What "managed" should include Managed WordPress hosting runs the full PHP and database stack for you on a platform tuned for WordPress. "Managed" is a marketing word with no fixed definition, so check that a plan includes: - Current, supported PHP versions with an easy way to switch. - Server-level full-page caching and an object cache (Redis or Memcached). - Automatic daily backups with self-service, one-click restores. - A staging environment with push-to-live. - Free TLS certificates, a web application firewall and malware scanning. - Optional or automatic WordPress core updates, and clear rules on plugin updates. - Support staff who understand WordPress, not just servers. WordPress.org's [hosting requirements](https://wordpress.org/about/requirements/) currently recommend PHP 8.3 or greater, MySQL 8.0+ or MariaDB 10.11+, and HTTPS support. Any serious host should meet these comfortably. ### Strengths - **Editor-friendly:** the familiar WordPress admin, the block editor and a huge plugin ecosystem. - **Dynamic features built in:** forms, search, memberships and [WooCommerce](/blog/woocommerce-performance-optimization/) run natively. - **Shared responsibility:** the host handles the server, while you, or your maintenance partner, handle the application. ### Limitations - **Uncached requests depend on PHP and the database.** Logged-in users, carts, checkouts and search results bypass the page cache, so plugin bloat and slow queries show up directly. - **Restrictions:** some hosts ban certain plugins, limit background processes or cap PHP workers, which matters for busy stores. - **The application is still yours to maintain.** Managed hosting doesn't keep your plugins and theme updated or secure. See our [WordPress security hardening checklist](/blog/wordpress-security-hardening/). ## VPS hosting ### How it works A VPS is a virtual machine with dedicated CPU, memory and storage allocations, where you have root access. You choose and configure everything: the operating system, web server (Nginx, Apache, Caddy), PHP-FPM or another runtime, the database, caching, firewall and backups. Cloud instances from the large providers work the same way for this purpose. ### Strengths - **Full control:** any language, any software, custom server configuration, background workers, WebSockets and scheduled jobs. - **Predictable resources:** no noisy shared environment and no arbitrary plugin bans. - **Good price-to-performance** for raw compute, if you have the skills to use it. - **The natural home for custom applications** that don't fit a CMS or static model. ### Limitations: you are the operations team An unmanaged VPS makes you responsible for security patching, firewall rules, intrusion prevention, TLS renewal, backups (and testing restores), monitoring, log rotation and capacity planning. Software lifecycles keep moving. PHP's [supported versions page](https://www.php.net/supported-versions.php) shows each branch getting two years of active support plus two of security fixes, and PHP 8.2 reaches end of life at the end of 2026. On a VPS, nobody upgrades it for you. A minimal Nginx configuration for a PHP application gives a sense of what you take on, and this is before hardening, caching and monitoring: ``` server { listen 443 ssl; http2 on; server_name www.example.com; root /var/www/example/public; index index.php; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # Long-lived caching for fingerprinted static assets location ~* \.(css|js|woff2|avif|webp|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; try_files $uri =404; } location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass unix:/run/php/php8.4-fpm.sock; } # Never serve hidden files such as .env or .git location ~ /\. { deny all; } } ``` Managed VPS plans and server-management panels can take over some of this work, at a cost somewhere between plain VPS and managed hosting pricing. ## Side-by-side comparison | | Factor | Static / Jamstack | Managed WordPress | VPS | Typical TTFB | Very low (CDN edge) | Low when cached; depends on PHP when not | Depends entirely on your configuration | Attack surface | Minimal | Moderate (PHP, plugins, admin login) | Whatever you expose | Server maintenance | None | Host handles server; you handle WordPress | All yours | Non-technical editing | Needs a headless/Git CMS | Excellent | Depends on the application | Dynamic features | Via APIs and functions | Native, plugin-based | Anything | E-commerce | Via third-party platforms | WooCommerce, natively | Any platform you install | Scaling under spikes | Excellent | Good with caching; limited by PHP workers | Manual or by your own automation | Skills needed | Front-end and build tooling | WordPress know-how | Linux administration | Best for | Landing pages, docs, content sites | Business sites, blogs, stores | Custom apps, special requirements ## Performance and responsibility in practice ### Server response time web.dev's [Time to First Byte guidance](https://web.dev/articles/ttfb) treats 0.8 seconds or less as a rough guide to a good TTFB. TTFB isn't a Core Web Vitals metric itself, but every millisecond of it delays Largest Contentful Paint. Whatever you choose, these levers matter most: - **Serve cached HTML** for anonymous visitors: CDN for static sites, full-page cache for WordPress, reverse proxy cache on a VPS. - **Put a CDN in front** of static assets at minimum, and of HTML where the platform supports it. - **Choose a server region close to your audience** for anything that can't be cached. - **Keep the stack current.** Newer PHP versions generally bring performance improvements as well as security fixes. ### Who is responsible for what? | | Task | Static / Jamstack | Managed WordPress | VPS | OS and server patches | Platform | Host | You | PHP and database versions | Not applicable | Host provides; you choose and test | You | Application, theme and plugin updates | You (dependencies) | You | You | Backups | Git history plus content source | Host (verify restores) | You | TLS certificates | Platform | Host | You (automate renewal) | Uptime monitoring | Recommended | Recommended | Essential **"Managed" doesn't mean "maintained"** - Even the best managed host usually leaves plugin, theme and custom-code updates to you. Outdated plugins remain one of the most common ways WordPress sites get compromised. - Decide before launch who will apply updates, test them and respond to incidents, whether that's someone in-house or a maintenance partner. ## Understanding the real cost of hosting Hosting prices are hard to compare because each model bills for different things. Rather than relying on headline figures, which change constantly, break the cost down into the same four parts for every option: ### 1. The platform fee Static platforms usually charge by bandwidth, build minutes, team seats and serverless function usage, and many small sites stay within free or entry tiers. Managed WordPress plans are typically priced per site or by monthly visits and storage, with higher tiers adding PHP workers, staging sites and priority support. A VPS is priced by CPU, memory and storage, and is often the lowest raw fee for the computing power you get. ### 2. Add-on services A static site that needs forms, search and a headless CMS may pay three separate subscriptions. A VPS may need a paid backup destination, an external monitoring service and a transactional email provider. Managed WordPress often bundles CDN, backups and a firewall, but premium plugins add their own yearly licences. ### 3. People's time This is the cost that changes the ranking most. Static hosting needs developer time for content changes unless editors have a CMS. Managed WordPress needs regular application updates and testing. A VPS needs ongoing system administration, plus someone available when something fails at the weekend. Put a realistic number of hours per month next to each option and multiply by what that time costs you. ### 4. The cost of failure Ask what an hour of downtime, a hacked site or a lost order would cost your business. A setup with automatic backups, tested restores and monitoring may cost more each month and still be the cheaper choice over a few years. ## Moving between hosting models Your first choice doesn't have to be permanent. Sites often move from one model to another as they grow. A brochure site becomes a WooCommerce store, or a WordPress blog is rebuilt as a static site to cut maintenance. A careful migration follows the same steps whichever direction it goes: - **Inventory everything:** files, database, scheduled tasks, email settings, DNS records, redirects and third-party integrations such as payment webhooks. - **Build and test on the new platform** using a temporary domain or hosts-file override, including forms, checkout and transactional emails. - **Lower the DNS TTL** a day or two in advance so the switch propagates quickly, and plan a short content freeze for sites with frequent updates or orders. - **Keep URLs identical** wherever possible. Where they must change, implement 301 redirects. Our [technical SEO launch checklist](/blog/technical-seo-checklist-new-websites/) covers this in detail. - **Keep the old hosting running** for a couple of weeks after the switch, as a fallback and a reference. Email deserves special mention. If your mailboxes live with your current web host, moving the website can break email unless MX, SPF, DKIM and DMARC records are carried over correctly. Many businesses use the move as an opportunity to separate email hosting from web hosting altogether. ## How to choose: a practical decision path Answer these questions in order: - **Do non-technical people need to edit content often?** If yes, lean towards managed WordPress, or static with a headless CMS if you have the development budget for it. - **Do you sell online?** For a full store with stock, variations and custom checkout logic, managed WordPress with WooCommerce is a strong default. Choose a plan with enough PHP workers for checkout traffic. - **Is the site mostly content that changes occasionally?** Static hosting gives you the best speed and security for the least ongoing effort. - **Do you run custom application logic,** such as background jobs, real-time features or non-PHP stacks? Choose a VPS or a managed application platform, and budget for operations. - **Who will look after it in two years?** If the honest answer is "nobody", choose the option with the least to maintain. ### Checks before you sign up - The renewal price, not just the introductory rate. - Resource limits: storage, bandwidth, PHP workers, and what happens when you exceed them. - Backup retention, off-site storage and whether restores are self-service. - Data-centre locations and whether they matter for your privacy obligations. - How easily you can export everything and leave. **Key takeaways** - Static/Jamstack hosting wins on speed, security and running costs for content that doesn't need server-side logic. - Managed WordPress is the practical default for editable business sites and WooCommerce stores, but the application still needs maintenance. - A VPS gives you total control along with total responsibility. Choose it for custom applications, not to save a few dollars. - Count people's time as part of the hosting cost. ## Choose the hosting that fits the people, not just the site There's no universally best hosting, only the best fit for your content, your features and the people who will run the site after launch. Get that match right and hosting fades into the background, which is where it belongs. If you're still shaping the overall project, our guide to [planning a website project](/blog/website-project-planning-guide/) shows where hosting fits into budget and scope. We build on all three models and recommend whichever fits. We can also take the ongoing work off your plate. Our [Website Care & Maintenance Plan](/service/website-care-maintenance-plan/) covers updates, backups, monitoring and security for $149 a month. [Get in touch](/contact-us/) and we'll recommend a hosting setup that suits your site and your team. ## FAQ **Q:** Is static hosting faster than WordPress hosting? **A:** Usually, for the first byte. A static site serves prebuilt files from a CDN with no server-side processing per request. A well-configured WordPress host with full-page caching can come close for anonymous visitors, but logged-in users, carts and other uncached requests still depend on PHP and database performance. **Q:** Do I need a VPS for a small business website? **A:** Rarely. A VPS gives you full control, but you also take on operating system updates, security hardening, backups and monitoring. Unless you need custom server software or have someone responsible for server administration, managed hosting is usually the safer and cheaper choice overall. **Q:** Can I host WordPress as a static site? **A:** Yes. A headless or static-export setup uses WordPress for editing and publishes static files to a CDN. It improves speed and security for content sites but adds build complexity, and dynamic features such as search, comments, forms and WooCommerce checkout need separate solutions. **Q:** What should I check before choosing a hosting provider? **A:** Check supported PHP and database versions, automatic backups and how restores work, staging environments, server locations and CDN options, security features, support quality, resource limits and the price at renewal rather than the introductory rate. Also confirm that you can export your site and leave easily. --- # How to Plan a Website Project: Scope, Budget and Timeline URL: https://hiddlins.com/blog/website-project-planning-guide/ Published: 2026-10-02 · Updated: 2026-10-02 Most website projects that run late or over budget don't fail in development. They fail in planning, when goals stay vague, scope is never written down and content is "nearly ready" for three months. Planning a website project doesn't need a project-management certificate. It needs a handful of clear decisions made in the right order. This guide walks through them: goals, audience and content, scope, choosing the right type of build, an honest budget, a realistic timeline, and the risks worth planning for before anyone writes a line of code. ## Start with goals, not pages "We need a new website" is a starting point, not a goal. Before you discuss design or technology, write down what the site must achieve and how you'll know whether it did. Good website goals are specific and measurable: - Generate qualified enquiries through the contact form or booking tool. - Sell products online and reduce manual order handling. - Cut repetitive support emails by answering common questions clearly. - Recruit staff, attract partners or support a funding round with credible information. - Replace an old site that is slow, insecure or impossible to update. For each goal, name a **metric** (form submissions, revenue, conversion rate, support volume) and record today's baseline if you have one. Those metrics guide every later trade-off. If a feature doesn't serve a goal, it's a candidate for phase two. They also define "done" in a way everyone can agree on. ### Identify the decision-makers Decide early who gives feedback and who approves. A project with one accountable decision-maker and a small group of named reviewers moves much faster than one where every stakeholder can reopen settled decisions. Write the names into the brief. ## Audience, content and structure ### Who is the site for? List your main audiences and the top questions each one brings. A prospective customer, an existing customer looking for support and a job applicant need different paths through the site. Keep it practical: two or three primary audiences, each with the actions you want them to take. This is the groundwork for the [UX decisions that move conversion rates](/blog/ux-principles-conversion/). ### Content inventory and sitemap If you have an existing site, list every page with its traffic and purpose, then decide for each: keep, rewrite, merge or delete. For a new site, draft a sitemap: the pages, their hierarchy and the main navigation. If you're unsure how visitors expect information to be grouped, a quick [card-sorting exercise](https://www.nngroup.com/articles/card-sorting-definition/) with a few real users is cheap and often revealing. ### Who writes the content? This is the most underestimated question in web projects. Decide who writes each page, who supplies photos and who approves the copy, and set dates for each. Design without real content tends to produce layouts that break when actual text arrives. We strongly recommend drafting at least your key pages (home, main services or products, about, contact) before design begins. **Content is the usual bottleneck** - Development rarely waits on code. It waits on copy, images, product data and approvals. - Put content deadlines in the plan with the same weight as development milestones, and assign a named owner to each. ## Define scope and prioritise ruthlessly Scope is the written list of what will be built: pages and templates, features, integrations and content migration. If it isn't written down, it isn't agreed. A useful way to keep scope honest is to sort every requirement into priority tiers, a method often called MoSCoW: - **Must have:** the site can't launch without it (contact form, core service pages, checkout for a store). - **Should have:** important, but launch could happen without it if necessary (blog, newsletter integration). - **Could have:** nice additions if time and budget allow (animated illustrations, a resource library). - **Won't have (this time):** explicitly parked for a later phase. Writing this list down prevents a lot of arguments. ### Think in templates, not pages Cost and effort are driven far more by the number of unique templates and features than by the page count. Fifty service pages that share one well-designed template cost much less than ten pages that are each different. When you list scope, group pages by template: home, service, article, product, landing page, contact. ### Don't forget the non-functional requirements These rarely appear in a first brief, but they shape the build and are much cheaper to plan than to retrofit: - **Performance:** set a performance budget for page weight, scripts and Core Web Vitals targets. web.dev's [performance budgets primer](https://web.dev/articles/performance-budgets-101) explains the idea. - **Accessibility:** aim for [WCAG](https://www.w3.org/WAI/standards-guidelines/wcag/) 2.2 level AA. Our [WCAG guide for small businesses](/blog/wcag-accessibility-guide-small-business/) covers what that means in practice. - **SEO and migration:** URL structure, redirects from the old site and structured data. See the [technical SEO launch checklist](/blog/technical-seo-checklist-new-websites/). - **Security and privacy:** forms, user accounts, payment handling, cookie consent and data retention. - **Editing:** who will update the site after launch, and how technical they are. ## Choose the right type of build Most projects fall into one of four categories. Picking the right one early avoids paying for complexity you don't need, or outgrowing a platform within a year. The prices below are our current fixed starting prices, listed so you have concrete reference points. Your final quote depends on scope. | | Build type | Best for | Typical scope | Our starting price | [Landing page](/service/landing-page-development/) | A campaign, product launch or single service with one clear call to action | One long-form page, form or booking integration, analytics | $1,490 | [WordPress website](/service/wordpress-website-development/) | Small and medium businesses that need a full site they can edit themselves | Several templates, blog, forms, SEO foundations, editor training | $3,900 | [WooCommerce store](/service/woocommerce-store-development/) | Selling physical or digital products, bookings or subscriptions | Catalogue, cart and checkout, payments, shipping and tax rules, order emails | $5,900 | [Custom web application](/service/custom-web-application-development/) | Unique workflows: portals, dashboards, SaaS products, internal tools | User accounts, business logic, integrations and APIs, data model | from $9,500 A useful rule of thumb: if your requirements are mostly content, a CMS like WordPress is usually the right answer. If they are mostly workflow and data, so that users log in to do things rather than read things, you're probably looking at a custom application, possibly alongside a marketing site. ## Build an honest budget A realistic budget has three parts: the build, the running costs and a contingency. Leaving out either of the last two is the most common budgeting mistake we see. ### 1. The build Our packages above are typical starting points. What moves a quote up from there is predictable: - More unique templates or complex layouts. - Integrations with CRMs, booking systems, ERPs, payment providers or custom APIs. - Content migration, especially large blogs or product catalogues with variations. - Multilingual sites, user accounts and role-based permissions. - Custom illustrations, photography, video or copywriting. If you have a figure in mind, share it. A budget range lets a good studio propose the best solution within it, instead of guessing and quoting something unusable. Our [pricing page](/pricing/) has a project cost calculator for a first estimate. ### 2. Running costs | | Item | Frequency | Notes | Domain name | Yearly | Renew automatically; register it in your own company's account | Hosting | Monthly or yearly | Varies widely by type; compared in our [hosting guide](/blog/choosing-web-hosting-static-wordpress-vps/) | Premium plugins, themes or SaaS tools | Usually yearly | Licences needed for updates and support | Maintenance and support | Monthly | Updates, backups, monitoring and fixes; our care plan is $149/month | Payment processing (stores) | Per transaction | Set by your payment provider | Content and marketing | Ongoing | New articles, campaigns, photography ### 3. Contingency Every project discovers something: an integration with a quirky API, a content gap, a new legal requirement. We recommend holding back 10–20% of the build budget as contingency. It is a planning habit, not a prediction. If you don't need it, it funds phase two. ## Set a realistic timeline A website project moves through recognisable phases. Durations vary with scope and how quickly feedback arrives, so treat the ranges below as a rough guide for a typical small-business WordPress site, not a promise. Landing pages compress this considerably, and stores and custom applications extend it. | | Phase | What happens | Rough duration | Your main input | Discovery & planning | Goals, scope, sitemap, technical decisions | 1–2 weeks | Brief, workshops, decisions | Content & design | Wireframes, visual design, copy drafting | 2–3 weeks | Content, feedback rounds | Development | Templates, features, integrations, CMS setup | 2–4 weeks | Answering questions, supplying assets | Content entry & QA | Populating pages, testing on devices, accessibility and performance checks | 1–2 weeks | Reviewing and approving pages | Launch & handover | Go-live, redirects, analytics, editor training | A few days | Final sign-off Our [process page](/process/) explains how we run each phase. Two timeline tips matter more than any others: - **Work back from a real deadline, not a wished-for one.** If you have a hard date such as a trade show, a product launch or the old hosting contract ending, say so on day one and let scope flex to meet it. - **Schedule feedback windows.** Agree in advance how many review rounds each phase gets and how many days each round takes. Feedback that takes two weeks to arrive costs two weeks. ## Write the brief Everything above fits into a short document that you can send to agencies or freelancers to get comparable quotes. One or two pages is enough. Here is a template you can copy: ``` # Website brief: [Company name] ## Goals & metrics - Primary goal: ... (metric: ..., current baseline: ...) - Secondary goals: ... ## Audiences - Audience 1: who they are, top questions, key action - Audience 2: ... ## Scope - Templates/pages: home, service (x6), article, contact, ... - Must have: ... - Should have: ... - Won't have (this phase): ... - Integrations: CRM, booking, payments, newsletter ... ## Content - Who writes copy: ... Photography: ... Deadline: ... ## Non-functional requirements - Performance targets, WCAG 2.2 AA, SEO/redirects, editing needs ## Constraints - Budget range: ... Hard deadline: ... Decision-maker: ... ## References - Sites we like (and why): ... ``` A brief like this tells a studio what you need and shows them you'll be a well-organised client. That usually leads to sharper quotes and fewer surprises. ## Compare quotes and choose a partner Send the same brief to each studio or freelancer you're considering, so the quotes are comparable. Quotes can still differ a lot, and the cheapest figure isn't always the cheapest project. When you compare them, look past the total: ### What a good proposal shows - **A restated understanding of your goals.** A proposal that plays your brief back in its own words, and questions parts of it, shows the team has actually thought about your business. - **Clear inclusions and exclusions.** Number of templates, design rounds, content entry, integrations, browser and device testing, accessibility and performance targets, and training. Ask what happens, and what it costs, when something falls outside them. - **Milestones and payment terms** tied to deliverables rather than dates alone. - **Ownership and access.** Confirmation that you will own the code, content, domain and accounts, with admin credentials handed over at launch. - **Post-launch support.** A warranty period for defects, and a clear option for ongoing maintenance if you want it. ### Questions worth asking - Who will actually work on the project, and who is my day-to-day contact? - How do you handle change requests once the scope is agreed? - Which plugins, frameworks or third-party services will the site depend on, and what do they cost each year? - How will you test performance and accessibility before launch? - Can I see live examples of similar work, and talk to you about the trade-offs in those projects? Pay attention to how each candidate answers as well as what they say. A partner who explains trade-offs plainly, admits what they would not recommend and puts commitments in writing is usually the one who delivers on time. You can see examples of our approach in our [portfolio](/portfolio/). ## Plan for risks and life after launch ### Common risks, and the cheap way to handle each - **Scope creep:** use a written change-request process that estimates cost and time before work starts, and keep a parking list for phase two. - **Lost SEO in a redesign:** build the redirect map and keep URLs stable where possible. - **Vendor lock-in:** make sure you own the domain, hosting account, code and content, and get admin access to everything. - **Single points of knowledge:** get documentation and editor training as part of handover. ### Plan the first 90 days after launch A launch is the start of a site's working life. Budget time to review analytics against your goals, fix issues real users uncover and publish the content you parked. Plan who will handle updates, backups and security monitoring. For WordPress and WooCommerce sites, that maintenance isn't optional, as our [WordPress security hardening checklist](/blog/wordpress-security-hardening/) explains. **Key takeaways** - Define measurable goals and one accountable decision-maker before talking about design. - Write scope down, prioritise with must/should/could/won't, and think in templates rather than pages. - Budget for the build, the running costs and a 10–20% contingency. - Treat content and feedback deadlines as seriously as development milestones. ## Turn your plan into a project A well-planned website project is calmer, cheaper and better than one that is figured out along the way. You don't need every answer before you start. You do need clear goals, a written scope, an honest budget and a timeline that includes the people who supply content and feedback. When you're ready, try the project cost calculator on our [pricing page](/pricing/), or look at our [WordPress Website Development](/service/wordpress-website-development/) package if a full business site is what you need. Prefer to talk it through? [Send us your brief](/contact-us/), rough or polished, and we'll help you shape it into a plan with a fixed price and a realistic timeline. ## FAQ **Q:** How much should I budget for a new website? **A:** It depends mostly on scope: the number of unique templates, content, integrations and whether you sell online. As a reference point, our fixed-price packages start at $1,490 for a landing page, $3,900 for a WordPress website and $5,900 for a WooCommerce store, with custom web applications from $9,500. Add ongoing costs for hosting, licences and maintenance, plus a contingency. **Q:** How long does it take to build a website? **A:** A focused landing page can often be delivered within a few weeks, a typical small-business WordPress site in roughly one to two months and an online store or custom application in longer, phased timelines. The biggest variable is usually not development but how quickly content and feedback arrive. **Q:** What should a website brief include? **A:** Goals and how you'll measure them, target audiences, a list of pages or a draft sitemap, required features and integrations, content responsibilities, brand assets, examples of sites you like and why, budget range, deadline and who signs off decisions. A one- or two-page brief is enough to get accurate quotes. **Q:** What is scope creep and how do I avoid it? **A:** Scope creep is the gradual addition of features or changes after the plan is agreed, which pushes out both budget and timeline. Prevent it with a written scope, a prioritised feature list, a change-request process that estimates cost and time before work starts, and a parking list for ideas that can wait for phase two. --- # Practical Machine Learning in the Browser with JavaScript URL: https://hiddlins.com/blog/machine-learning-in-the-browser/ Published: 2026-09-22 · Updated: 2026-09-22 Machine learning is no longer something only a server can do. Browsers now ship WebAssembly with SIMD and threads, and increasingly WebGPU, so a web page can classify images, transcribe speech, embed text for semantic search or run a small language model entirely on the user's device. Nothing leaves the device, and you pay no per-request inference bill. This guide covers how to do it in practice with TensorFlow.js, ONNX Runtime Web and Transformers.js, when it is the right choice, and how to handle the biggest constraint: model size. ## Why run machine learning in the browser? Client-side inference isn't always the right architecture, but when it fits, the benefits are concrete: - **Privacy by design.** The user's photos, voice recordings or documents are processed locally. For sensitive inputs such as ID documents, health notes or private messages, not having to transmit the data at all is the strongest privacy guarantee you can give. - **Low latency.** Once the model is loaded, there is no network round trip, so real-time uses like webcam pose tracking, live captioning or as-you-type suggestions become feasible. - **Cost that doesn't scale with usage.** The user's hardware does the compute. Your costs are hosting static model files, which a CDN caches cheaply. - **Offline capability.** With the model cached, features keep working without a connection, which suits progressive web apps and field tools. The trade-offs are just as real: a one-off model download, wide variation in device capability, and memory limits, especially on mobile. Most of this guide is about managing those. ## Use cases that work well today It helps to think in terms of tasks, not models. These categories are well served by small, browser-friendly models and mature tooling: ### Vision - **Image classification and tagging**, for example suggesting categories when a user uploads a product photo, or rejecting blurry or wrong-orientation document scans before upload. - **Object and pose detection** for fitness apps, gesture controls, virtual try-on and accessibility tools, often combined with a canvas overlay like the one in our [Canvas animation tutorial](/blog/canvas-particle-animation-tutorial/). - **Background removal and segmentation** for profile pictures and product images, without uploading the original photo. ### Text - **Embeddings and semantic search** over help centres, documentation or product catalogues. - **Classification**: sentiment, topic routing for contact forms, detecting language before choosing a translation path. - **Small generative models** for autocomplete, rewriting or summarising short passages, where a quantised model of a few hundred million parameters is often enough. ### Audio - **Speech recognition** with compact Whisper-family models for dictation and captions, keeping recordings on the device. - **Keyword spotting and audio classification** for voice commands or sound-event detection. What these have in common is bounded input, tolerance for occasional imperfect output, and a clear user benefit from privacy or immediacy. If a feature needs encyclopaedic knowledge or long, high-stakes reasoning, a large server-hosted model is usually the better tool. ## The runtime layer: WebAssembly, WebGL, WebGPU and WebNN Every browser ML library sits on top of one or more backends, the browser technologies that actually run the maths. Understanding them explains most of the performance differences you'll see. | | Backend | Runs on | Strengths | Limitations | WebAssembly (Wasm) | CPU | Available practically everywhere; broadest operator coverage; SIMD and multithreading speed it up considerably | Slower than GPU for large models; threads require cross-origin isolation | WebGL | GPU | Wide support; mature in TensorFlow.js | A graphics API repurposed for compute; overheads and precision quirks | WebGPU | GPU | Real compute shaders; much better suited to modern ML workloads | Not yet available in every browser/OS combination; secure contexts only | WebNN | CPU, GPU or NPU | Lets the browser hand work to OS-level ML acceleration, including neural processing units | Emerging API with limited availability; treat as progressive enhancement [MDN's WebGPU documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API) currently marks the API as having limited availability and notes that it only works in secure contexts. The practical pattern is to detect WebGPU, use it when present, and fall back to WebAssembly otherwise: ``` async function pickDevice() { if ('gpu' in navigator) { try { const adapter = await navigator.gpu.requestAdapter(); if (adapter) return 'webgpu'; } catch (err) { // Adapter request can fail on blocklisted drivers; fall through } } return 'wasm'; } ``` ## Choosing a library Three libraries cover most real-world projects. They overlap, but each has a clear sweet spot. ### TensorFlow.js [TensorFlow.js](https://www.tensorflow.org/js) is the most established option. It runs pre-trained models, converts TensorFlow/Keras models, and is unusual in supporting **training** in JavaScript, including transfer learning on the user's own data in the browser. It has CPU, WebGL, Wasm and WebGPU backends and a large collection of ready-made models for pose detection, face landmarks, object detection and more. ### ONNX Runtime Web ONNX is an open model format that most frameworks can export to, PyTorch in particular. [ONNX Runtime Web](https://onnxruntime.ai/docs/tutorials/web/) runs those models in the browser with Wasm, WebGL, WebGPU and WebNN execution providers. The Wasm provider supports all ONNX operators, while the GPU providers support a subset. That makes it the natural choice when your data science team trains in Python and you need a reliable path to production on the web. ### Transformers.js [Transformers.js](https://huggingface.co/docs/transformers.js/index) (published on npm as @huggingface/transformers) mirrors the Python transformers pipeline API and runs ONNX-converted models from the Hugging Face Hub, using ONNX Runtime underneath. In a few lines you get tasks like sentiment analysis, embeddings, zero-shot classification, translation, summarisation, speech recognition and image segmentation. It is the fastest way to prototype. | | | TensorFlow.js | ONNX Runtime Web | Transformers.js | Best for | TF/Keras models, in-browser training | Custom models exported from PyTorch and other frameworks | Ready-made NLP, vision and audio tasks | Abstraction level | Tensors and layers | Inference sessions | High-level task pipelines | Model source | TF Hub/Kaggle models, converted models | Any ONNX file | Hugging Face Hub (ONNX weights) | GPU path | WebGL, WebGPU | WebGPU, WebGL, WebNN | WebGPU (via ONNX Runtime) | Training | Yes | Inference-focused | Inference only ## Example: semantic search with Transformers.js in a Web Worker A useful, privacy-friendly feature for many sites is semantic search over your own content, matching meaning rather than exact keywords. The pattern: precompute embeddings for your articles at build time, ship them as JSON, and embed only the user's query in the browser. Run the model in a **Web Worker** so that loading and inference never block the main thread, which would hurt responsiveness and your INP score: ``` // embed-worker.js (load with: new Worker('embed-worker.js', { type: 'module' })) import { pipeline } from '@huggingface/transformers'; let extractorPromise = null; function getExtractor(device) { if (!extractorPromise) { extractorPromise = pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2', { device, // 'webgpu' or 'wasm' dtype: 'q8', // quantised weights: smaller download progress_callback: (p) => self.postMessage({ type: 'progress', p }), }); } return extractorPromise; } self.onmessage = async ({ data }) => { const extractor = await getExtractor(data.device); const output = await extractor(data.text, { pooling: 'mean', normalize: true }); self.postMessage({ type: 'result', vector: Array.from(output.data) }); }; ``` On the main thread, the query vector is compared with your precomputed article vectors. Because the vectors are normalised, cosine similarity reduces to a dot product: ``` function dot(a, b) { let sum = 0; for (let i = 0; i < a.length; i++) sum += a[i] * b[i]; return sum; } function rank(queryVector, articles, topK = 5) { return articles .map((article) => ({ ...article, score: dot(queryVector, article.vector) })) .sort((x, y) => y.score - x.score) .slice(0, topK); } ``` The search query never touches your server. For a few hundred articles, a brute-force comparison like this takes milliseconds, and you don't need a vector database. ## Example: a custom model with ONNX Runtime Web When the model is your own, for example a product-image classifier fine-tuned in PyTorch and exported with torch.onnx.export, ONNX Runtime Web gives you direct control over the session. List execution providers in order of preference and the runtime falls back if one isn't available: ``` import * as ort from 'onnxruntime-web/webgpu'; const session = await ort.InferenceSession.create('/models/classifier.onnx', { executionProviders: ['webgpu', 'wasm'], graphOptimizationLevel: 'all', }); // Preprocessed image: Float32Array of shape [1, 3, 224, 224] async function classify(pixels) { const input = new ort.Tensor('float32', pixels, [1, 3, 224, 224]); const results = await session.run({ [session.inputNames[0]]: input }); const logits = results[session.outputNames[0]].data; return softmax(Array.from(logits)); } function softmax(values) { const max = Math.max(...values); const exps = values.map((v) => Math.exp(v - max)); const total = exps.reduce((a, b) => a + b, 0); return exps.map((e) => e / total); } ``` Preprocessing has to match training exactly: resize method, channel order, normalisation mean and standard deviation. In our experience, mismatched preprocessing causes more "the model works in Python but not in the browser" bugs than anything else. Validate the outputs against the Python version on a handful of test images before shipping. ## Example: TensorFlow.js and memory discipline TensorFlow.js exposes tensors directly, which gives you flexibility and one responsibility: GPU-backed tensors are not garbage-collected like ordinary JavaScript objects. Wrap synchronous work in tf.tidy() and dispose of anything you keep: ``` import * as tf from '@tensorflow/tfjs'; await tf.setBackend('webgl'); // or 'wasm' / 'webgpu' with the matching backend package await tf.ready(); const model = await tf.loadGraphModel('/models/mobilenet/model.json'); function predict(imageElement) { return tf.tidy(() => { const input = tf.browser.fromPixels(imageElement) .resizeBilinear([224, 224]) .toFloat() .div(127.5).sub(1) // scale to [-1, 1] as the model expects .expandDims(0); return model.predict(input).dataSync(); }); } // Watch for leaks during development console.log(tf.memory().numTensors); ``` If numTensors keeps climbing as the user interacts, you have a leak. On a phone, a leak like that ends in a crashed tab within minutes. ## Model size: the trade-off that shapes everything A server can load a model once. A browser has to download it, at least on the first visit. A model's download size is roughly its parameter count multiplied by the bytes stored per parameter, which is why **quantisation**, storing weights at lower precision, matters so much on the web. | | Precision | Bytes per parameter | Approx. size of a 100M-parameter model | Typical trade-off | fp32 | 4 | ~400 MB | Reference accuracy; usually too large for casual web use | fp16 | 2 | ~200 MB | Near-identical accuracy for most models; good fit for WebGPU | int8 (q8) | 1 | ~100 MB | Small accuracy loss for many tasks; good default for Wasm | 4-bit (q4) | 0.5 | ~50 MB | Larger quality impact; often what makes small LLMs feasible These figures are simple arithmetic and leave out file overheads, but they show the scale of the decision. Transformers.js exposes this directly through its dtype option. Its documentation lists fp32 as the default on WebGPU and q8 on Wasm, with fp16 and q4 available depending on the model. ### Strategies for managing size - **Choose task-specific small models.** A distilled sentence-embedding model or a MobileNet-class vision model is tens of megabytes or less, and often good enough. Start small and move up only if quality requires it. - **Load on intent, not on page load.** Download the model when the user opens the feature, not when they land on the page. Your [Core Web Vitals](/blog/core-web-vitals-guide/) will thank you. - **Cache aggressively.** Serve model files with long-lived, immutable cache headers and versioned filenames. Transformers.js also caches downloaded files using the browser's Cache API by default, so repeat visits skip the download. - **Show honest progress.** A progress bar with megabytes remaining is far better than an unexplained spinner. - **Respect constrained users.** Check navigator.connection?.saveData where available, and offer a server-side or non-ML fallback for low-memory devices. **Enabling multithreaded WebAssembly** - Wasm threads need SharedArrayBuffer, which browsers only expose on cross-origin isolated pages. Serve the page with Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp, and check self.crossOriginIsolated. - Isolation can break third-party embeds such as video players and some ad or analytics scripts, so test the whole page, not just the ML feature. ## Privacy, security and knowing when not to ### Keeping the privacy promise "Runs on your device" is a strong claim, so make sure it is true. Audit the feature's network traffic in DevTools. Analytics events, error-tracking payloads and session-replay tools can quietly capture the very inputs you promised to keep local. If you describe the feature as private in your UI or privacy policy, back it up by checking what actually leaves the device. ### Your model is public Anything you ship to the browser can be downloaded and inspected. Don't deploy a model whose weights are a trade secret, and never rely on client-side inference for security decisions such as fraud checks or content moderation that must not be bypassed. A user can always modify the result before it reaches your server. ### When a server is the better choice - The model is too large to download comfortably (large generative models, high-accuracy vision models). - You need consistent results and latency on every device, including low-end phones. - The model or its outputs must stay confidential, or results must be trusted server-side. - Inference needs data that lives on the server anyway. Hybrid setups work well too: a small on-device model handles the common, latency-sensitive cases and escalates hard ones to a server, with the user's consent where data is sensitive. **Key takeaways** - Browser ML gives you privacy, low latency and usage-independent costs, at the price of downloads and device variability. - Use Transformers.js for ready-made tasks, ONNX Runtime Web for your own exported models, and TensorFlow.js for TF models or in-browser training. - Prefer WebGPU when available, always fall back to WebAssembly, and run inference in a Web Worker. - Quantise, load on intent and cache. Model size is the constraint that shapes everything else. ## Bringing ML features to your product On-device machine learning has moved from demos to dependable product features: private document scanning, smart search, accessibility aids like live captions, and interactive visual tools. The libraries are mature enough that most of the work is ordinary engineering: choosing a model that fits, keeping the main thread free and treating megabytes with respect. If you are weighing whether you need a framework around all this, our take on [modern JavaScript without the bloat](/blog/vanilla-javascript-without-frameworks/) applies here too. For presenting model output visually, see our comparison of [SVG, Canvas and WebGL](/blog/web-data-visualization-svg-canvas-webgl/). Have an idea for an ML-powered feature, or a model that needs to run on the web? Our [Custom Web Application Development](/service/custom-web-application-development/) service covers prototyping, model integration and production hardening. [Tell us what you're building](/contact-us/) and we'll help you decide whether it belongs in the browser, on a server or in both. ## FAQ **Q:** Can a browser really run machine learning models fast enough to be useful? **A:** Yes, for the right models. Image classification, object detection, text embeddings, sentiment analysis, speech recognition and small language models all run well in modern browsers, especially with WebGPU. Very large generative models are still better served from a server or a dedicated API. **Q:** Is browser-based ML private? **A:** Inference happens on the user's device, so input data such as photos, audio or text does not need to leave the browser. That is a real privacy benefit, but it only holds if your page doesn't also send that data to analytics or logging services. The model file itself is public, since anyone can download it. **Q:** Which library should I start with: TensorFlow.js, ONNX Runtime Web or Transformers.js? **A:** For ready-made NLP, vision or audio tasks using models from the Hugging Face Hub, start with Transformers.js. If you have a model trained in PyTorch or another framework, export it to ONNX and use ONNX Runtime Web. Choose TensorFlow.js if your model comes from the TensorFlow ecosystem or you want to train or fine-tune in JavaScript. **Q:** Does WebGPU work in every browser? **A:** Not yet universally. MDN still marks WebGPU as having limited availability, and it requires a secure (HTTPS) context. Always feature-detect with navigator.gpu and fall back to the WebAssembly backend, which runs on effectively every modern browser. --- # Generative Engine Optimization: Getting Your Brand Cited by AI Search URL: https://hiddlins.com/blog/generative-engine-optimization-ai-search/ Published: 2026-09-12 · Updated: 2026-09-12 People increasingly get answers instead of a list of blue links. Google's AI Overviews and AI Mode, Gemini, ChatGPT search, Perplexity and Claude all write a response and cite a handful of sources. Generative engine optimization (GEO) is the practice of making your brand one of those sources. Some of it is new, but most of it is good SEO done with more discipline. This guide explains how answer engines actually find and cite pages, what you can control (crawler access, entity clarity, structured data, content you can quote) and where the hype runs ahead of the evidence. ## What generative engine optimization is, and what it isn't A large language model doesn't "search" in the classic sense when it answers from memory. When an assistant shows citations, though, it is almost always using **retrieval-augmented generation**. The system runs one or more searches, fetches or looks up candidate pages, pulls out relevant passages, and writes an answer grounded in them. The links you see are the passages it relied on. That has a practical consequence. **To be cited, you first have to be retrieved.** Retrieval depends on search indexes and crawlers, which is familiar SEO territory. GEO then adds a second question: once your page is among the candidates, is it easy for the model to understand, trust and quote? What GEO is not: - **A way to "inject" your brand into a model's training data.** What a model learned during training is beyond your control and changes only when it is retrained. - **A set of secret markup tricks.** Google says plainly that there are no special requirements, machine-readable AI files or special schema needed to appear in its AI features (more on that below). - **Guaranteed.** Answers vary between runs, users, locations and model versions. You are improving your odds, not buying a placement. ## How the major answer engines find and cite sources Each provider combines its own crawlers, search indexes and partners differently, and the details change often. The broad picture as of late 2026: ### Google AI Overviews and AI Mode Both are built on Google Search's index. Google's documentation on [AI features and your website](https://developers.google.com/search/docs/appearance/ai-features) describes a "query fan-out" technique: the system issues several related searches across subtopics and can surface a wider set of supporting pages than a single classic query would. The requirement for inclusion is simply that a page is indexed and eligible to appear in Search with a snippet. Google lists no extra technical requirements. ### Gemini The Gemini app can ground answers in Google Search results. Use of crawled content for Gemini model training and for grounding in other Google products is controlled by the Google-Extended robots.txt token. Google's [crawler documentation](https://developers.google.com/search/docs/crawling-indexing/google-common-crawlers) notes that it doesn't affect inclusion or ranking in Google Search. ### ChatGPT search OpenAI separates its crawlers by purpose: OAI-SearchBot surfaces websites in ChatGPT's search features, GPTBot collects content that may be used to train foundation models, and ChatGPT-User fetches pages when a user's request triggers a visit. Their [crawler documentation](https://developers.openai.com/api/docs/bots) notes that sites which opt out of OAI-SearchBot won't appear in ChatGPT search answers. ### Perplexity Perplexity runs PerplexityBot to index and link websites in its answers, and Perplexity-User for fetches a user triggers. It says PerplexityBot isn't used to crawl content for training foundation models. ### Claude Anthropic documents three agents: ClaudeBot collects content for model training, Claude-SearchBot improves the relevance of search results, and Claude-User fetches pages when a person asks Claude a question that needs web content. | | Token / user agent | Operator | Main purpose | Blocking it affects | Googlebot | Google | Search indexing | Google Search and AI Overviews/AI Mode | Google-Extended | Google | Control token (no separate crawler) | Gemini training and grounding use; not Search ranking | OAI-SearchBot | OpenAI | ChatGPT search | Appearing in ChatGPT search answers | GPTBot | OpenAI | Model training | Use of content in future training | PerplexityBot | Perplexity | Search index | Appearing in Perplexity answers | ClaudeBot | Anthropic | Model training | Use of content in future training | Claude-SearchBot | Anthropic | Search quality | Visibility in Claude's search results | CCBot | Common Crawl | Open web archive | Inclusion in Common Crawl datasets, which many AI projects use **User-triggered fetchers are different** - Agents like ChatGPT-User, Perplexity-User and Claude-User act on a specific person's request. Providers state that robots.txt rules may not apply to them in the same way as to automatic crawlers. Read each provider's current documentation if this matters to you. ## Crawler access: a deliberate robots.txt policy The most common GEO problem we see isn't weak content. It is sites that block AI search crawlers by accident: a security plugin, a CDN bot-management rule or a copied robots.txt snippet that shuts out everything with "bot" in the name. Decide on a policy deliberately, along two separate axes: - **Search and citation crawlers:** if you want to be cited, allow them. - **Training crawlers:** a business and licensing decision. Blocking them doesn't remove you from AI search with the providers that separate the two. Here is a policy that welcomes AI search but opts out of training: ``` # Search engines and AI search/citation crawlers: allowed User-agent: Googlebot User-agent: Bingbot User-agent: OAI-SearchBot User-agent: PerplexityBot User-agent: Claude-SearchBot Allow: / # Model-training crawlers and controls: opted out User-agent: GPTBot User-agent: ClaudeBot User-agent: Google-Extended User-agent: CCBot Disallow: / # Everyone else User-agent: * Disallow: /wp-admin/ Allow: /wp-admin/admin-ajax.php Sitemap: https://www.example.com/sitemap_index.xml ``` Two caveats. First, robots.txt is a voluntary standard. Reputable operators honour it, but it isn't access control. Second, blocking Google-Extended is a trade-off you should make knowingly. It stops grounding use in Gemini-family products outside Search, which some brands want and others don't. Whatever you choose, also check your CDN or firewall. Robots.txt allowing a crawler means nothing if a bot-protection rule returns a 403 or a challenge page to it. ## Entity clarity: make it obvious who you are Language models reason about **entities**: organisations, people, products, places, and the relationships between them. If your brand name is ambiguous, inconsistent or rarely tied to what you do, a model has a hard time deciding that you are the right source to cite for a question in your field. ### Practical steps - **Use one canonical name.** Use the same spelling, capitalisation and legal-versus-trading name everywhere: site header, footer, social profiles, directories and press mentions. - **Write a precise About page.** Say in plain sentences what you are, what you do, who you serve and where you operate. "We are an independent web development studio building WordPress sites and custom web applications" is far more useful to a machine than a page of slogans. - **State relationships explicitly.** Link your services, products and topic pages to each other with descriptive anchor text, so the site itself lays out what you are an authority on. - **Connect your profiles.** Link from your site to your official profiles and from those profiles back to your site, and list them in sameAs in your Organization markup. ## Structured data: Organization, Article and FAQPage Let's be clear about what structured data does here. Google says that no special schema is required for AI Overviews or AI Mode, and that your markup must match the visible content of the page. Still, JSON-LD built on schema.org types is an unambiguous, machine-readable statement of facts, and it costs little to maintain. It supports regular rich results and entity understanding, and it removes guesswork for any system that parses it. ### Organization Put this on the homepage (or sitewide) with your name, URL, logo, contact point and sameAs profiles. This is where entity clarity becomes machine-readable. ### Article On blog posts and guides, Article (or BlogPosting) markup states the headline, publication and modification dates, author and publisher. Accurate dates matter because answer engines care about freshness for many queries. ``` ``` ### FAQPage FAQPage markup describes real question-and-answer content on a page. Google has limited FAQ rich results to a small set of authoritative government and health sites since 2023, so don't expect expandable FAQs in classic results. The markup still describes the content accurately, and question-shaped content maps naturally onto the questions people type into assistants. Only mark up questions and answers that are visible on the page. ## Writing content that gets cited Retrieval systems work on **passages**, not whole pages. A page that buries its answer in the sixth paragraph of a narrative is harder to quote than one that states it plainly near a matching heading. Pages that get cited tend to share these traits: - **Answer first.** Open each section with a direct one- or two-sentence answer, then expand. This is also good writing for skimming humans. - **Self-contained passages.** Each section should make sense on its own, without "as mentioned above". Repeat the subject noun instead of relying on "it". - **Descriptive headings.** Phrase headings the way people ask: "How long does a WordPress migration take?" rather than "Timelines". - **Structure that extracts cleanly.** Tables for comparisons, numbered lists for procedures and definitions in a single sentence. [Semantic HTML](/blog/semantic-html-seo-accessibility/) makes this structure explicit. - **Specifics.** Numbers, thresholds, version numbers, dates and named standards. A vague claim has nothing in it for a model to cite. - **Visible freshness and accountability.** Show updated dates, a clear author or publisher, and an editorial policy explaining how content is checked. Technical health still underpins all of this. A page that renders its main content only after heavy client-side JavaScript, or that responds slowly, may be retrieved less reliably. Start with our [technical SEO checklist](/blog/technical-seo-checklist-new-websites/). ## Original research and consistent brand mentions ### Give models something they can't get elsewhere If twenty pages say the same thing, an answer engine can cite any of them, or none. Original information breaks that tie. You don't need a research department to produce it: - Publish aggregated, anonymised data from your own work, such as typical project timelines or the most common issues found in audits, with a clear methodology. - Run your own benchmarks, documenting the setup well enough that someone else could reproduce them. - Write definitive documentation for your own products, pricing and processes. For questions about you, you should be the best source. - Create explanatory tools such as calculators, checklists and decision tables that others reference. ### Be described consistently off-site Answer engines also learn about you from other sites: directories, industry publications, partner pages, reviews and community discussions. Consistency counts for more than volume here. Make sure the description, category and core facts about your business match everywhere you control them. Earn mentions in places that are relevant to your field. A short, accurate mention in a respected industry resource does more than dozens of low-quality listings. ## The llms.txt proposal: what it is and how much it matters [llms.txt](https://llmstxt.org/) is a proposal for a Markdown file at /llms.txt that gives language models a concise, curated guide to a site. It has a required H1 with the site name, an optional blockquote summary, and H2 sections listing key links with short notes. An "Optional" section holds secondary links. The proposal also suggests offering clean Markdown versions of important pages. ``` # Example Studio > Independent web development studio building WordPress sites, > WooCommerce stores and custom web applications. ## Services - [WordPress development](https://www.example.com/services/wordpress/): Custom themes and block-based sites - [Performance audits](https://www.example.com/services/audit/): Core Web Vitals and technical SEO reviews ## Guides - [Technical SEO checklist](https://www.example.com/blog/technical-seo-checklist/): Pre-launch checks ## Optional - [Company policies](https://www.example.com/policies/) ``` Be realistic about it. **llms.txt is a proposal, not a standard, and adoption is uneven.** It is popular with developer-documentation sites and some AI coding tools. The major answer engines haven't published consistent commitments to use it in ranking or citation, and Google explicitly says that no special AI text files are needed for its AI features. We see it as a cheap, harmless experiment that is worth doing if you maintain good documentation. It won't fix weak fundamentals. ## Measuring results Measurement is still rough, so combine several signals: | | Signal | Where to find it | What it tells you | Google AI features traffic | Search Console Performance report, "Web" search type | Clicks and impressions, including AI Overviews and AI Mode (not separated out) | Assistant referrals | Analytics referrers such as chatgpt.com, perplexity.ai, gemini.google.com, claude.ai | Which assistants send visitors, and to which pages | Crawler activity | Server or CDN logs filtered by user agent | Whether search and citation bots are reaching your pages at all | Prompt testing | A fixed list of customer questions, checked monthly | Whether, and how accurately, you are mentioned or cited Treat prompt testing as directional. Answers vary between sessions, accounts and locations, so look for trends across a stable question set, not single screenshots. **Key takeaways** - To be cited, you must first be retrieved. Indexing, crawler access and technical health come first. - Separate AI search crawlers from training crawlers in robots.txt, and check that your CDN doesn't silently block them. - Make your entity unambiguous: consistent name, precise About page, Organization markup with sameAs. - Write answer-first, self-contained passages, and publish information others can't. - Treat llms.txt as an optional experiment, not a requirement. ## Be the source worth citing Generative engine optimization rewards the same things good SEO always has, applied more strictly: crawlable pages, clear structure, unambiguous facts and content that adds something new. The new parts are mostly about access decisions and describing your brand consistently. Speed matters too. Pages that load and render quickly are easier for every crawler to process, which our [Core Web Vitals guide](/blog/core-web-vitals-guide/) covers in detail. Want to know how AI search engines see your site today? Our [Performance & Technical SEO Audit](/service/performance-seo-audit/) reviews crawler access, structured data, entity signals and content structure alongside the classic technical checks. [Contact us](/contact-us/) and we'll take a look. ## FAQ **Q:** Is generative engine optimization different from SEO? **A:** Mostly it is SEO with a different emphasis. AI search features retrieve pages from search indexes or their own crawls, so crawlability, indexing and quality content still come first. GEO adds attention to entity clarity, passages that can be quoted on their own, original information and how consistently your brand is described across the web. **Q:** Do I need an llms.txt file to appear in AI answers? **A:** No. llms.txt is a community proposal, and support for it varies between AI providers. Google states that no special AI files or markup are needed to appear in AI Overviews or AI Mode. Publishing one is low-cost and harmless, but treat it as an experiment rather than a requirement. **Q:** If I block GPTBot, will my site disappear from ChatGPT? **A:** Not necessarily. OpenAI documents GPTBot as the crawler for model training and OAI-SearchBot as the crawler for ChatGPT search. You can block training while still allowing search. Check each provider's documentation, because the separation between training, search and user-triggered fetching differs from company to company. **Q:** How can I tell whether AI search sends me traffic? **A:** Google includes AI Overviews and AI Mode traffic in the Search Console Performance report under the Web search type. For other assistants, look for referrals from domains such as chatgpt.com, perplexity.ai, gemini.google.com and claude.ai in your analytics, and run regular manual checks of the questions your customers actually ask. --- # The Technical SEO Checklist for Launching a New Website URL: https://hiddlins.com/blog/technical-seo-checklist-new-websites/ Published: 2026-09-02 · Updated: 2026-09-02 A new website gets one first impression with search engines. If the launch ships with a leftover noindex tag, a staging domain in the canonical URLs or a missing redirect map from the old site, you can lose weeks of visibility while crawlers sort out the mess. This technical SEO checklist covers what we verify on every launch: crawling, indexing, canonical URLs, redirects, structured data, performance, security and the first 30 days after go-live. Each item is practical and testable, and none of it depends on tricks. ## Why technical SEO comes first Content and links decide how well you rank. Technical SEO decides whether you can rank at all. A search engine has to **discover** a URL, **crawl** it, **render** it, decide whether it is worth **indexing**, and then pick a **canonical** version among any duplicates. A failure at any of those steps hides your best content, however good it is. New sites are especially exposed for three reasons: - **No history.** Search engines have no prior signals about your domain, so they crawl cautiously, and a confusing structure wastes the attention they do give. - **Development leftovers.** Staging settings like "Discourage search engines" in WordPress, hard-coded test URLs and placeholder content often survive into production. - **Redesign migrations.** If the new site replaces an old one, every URL that changes without a redirect throws away the links and rankings the old page earned. Google's own [SEO Starter Guide](https://developers.google.com/search/docs/fundamentals/seo-starter-guide) is a good baseline. The checklist below turns those principles into concrete launch tasks. ## Protect staging, then plan the switch Most launch-day disasters begin on the staging server. Your development environment has to stay invisible while you build, and every one of those protections has to come off cleanly when you go live. ### Use authentication, not just robots.txt A Disallow: / rule in robots.txt asks crawlers not to fetch pages, but it does not stop a URL from being indexed if someone links to it. The URL can still appear in results without a description. The reliable option is HTTP authentication on the whole staging host, with a noindex response header as a second layer: ``` # Staging server only: password-protect and noindex everything server { server_name staging.example.com; auth_basic "Staging"; auth_basic_user_file /etc/nginx/.htpasswd; add_header X-Robots-Tag "noindex, nofollow" always; } ``` ### Write a launch-switch list Write down every environment-specific setting before launch day, so nobody is relying on memory at 11 p.m. Typical entries include: - WordPress Settings → Reading → Discourage search engines unchecked on production. - X-Robots-Tag headers and removed. - Site URL, home URL and any hard-coded staging domains replaced in the database (use a serialisation-safe search-and-replace tool for WordPress). - Analytics and tag manager IDs switched from test to production properties. - Transactional email and payment gateways moved out of sandbox mode. ## Crawlability: robots.txt, status codes and internal links ### A minimal, correct robots.txt Most small and medium sites need a short robots.txt. Its job is to keep crawlers out of low-value areas (internal search results, cart and account pages) and to point to your sitemap. It is not a security tool. Anything you list is publicly readable. Google's [robots.txt introduction](https://developers.google.com/search/docs/crawling-indexing/robots/intro) explains the syntax in detail. ``` User-agent: * Disallow: /wp-admin/ Allow: /wp-admin/admin-ajax.php Disallow: /?s= Disallow: /search/ Disallow: /cart/ Disallow: /checkout/ Disallow: /my-account/ Sitemap: https://www.example.com/sitemap_index.xml ``` **Do not block CSS or JavaScript** - Google renders pages much as a browser does. If robots.txt blocks your theme's stylesheets or scripts, Google may see a broken layout and misjudge the page, including how it looks on mobile. - Do not use robots.txt to remove pages from the index. A page blocked from crawling can't show Google its noindex tag. ### Status codes that tell the truth Every URL should return the status code that matches what it actually is: - **200** for real, indexable content. - **301** (or 308) for permanent moves. Use 302/307 only for genuinely temporary situations. - **404** or **410** for content that does not exist. A "page not found" message served with a 200 status is a soft 404, and it wastes crawl attention. - **503** with a Retry-After header during planned maintenance, so crawlers come back later instead of recording errors. ### Internal linking and crawl depth Crawlers find pages by following links. Every important page should be reachable through normal links. JavaScript click handlers don't count. Keep key pages within about three clicks of the homepage. Orphan pages, which appear in the sitemap but have no internal links, are a common finding in audits. They signal that the site's own navigation doesn't consider them important. Clean, [semantic HTML](/blog/semantic-html-seo-accessibility/) with real navigation landmarks helps crawlers and assistive technology alike. ## Indexability and canonical URLs ### Pick one canonical host Your site is reachable at four or more variants unless you consolidate them: http:// and https://, with and without www, sometimes with and without trailing slashes. Pick one form and 301-redirect every other variant to it in a single hop: ``` # Redirect all HTTP and non-www traffic to https://www.example.com server { listen 80; server_name example.com www.example.com; return 301 https://www.example.com$request_uri; } server { listen 443 ssl; server_name example.com; # ssl_certificate ... (certificate must cover the bare domain too) return 301 https://www.example.com$request_uri; } ``` ### Self-referencing canonical tags Every indexable page should declare its preferred URL with an absolute, self-referencing canonical tag. This protects you when the same content is reachable under tracking parameters, sort orders or session IDs: ``` ``` A canonical tag is a strong hint, not a command. Google weighs it against redirects, internal links and sitemap entries, so all of those signals should agree. Google's guide to [specifying canonical URLs](https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls) covers the edge cases. The most common launch mistake is canonical tags that still point at the staging domain. Crawl the live site and check for this specifically. ### Thin and duplicate pages Content management systems generate pages you never asked for: tag archives with a single post, author archives on a single-author blog, attachment pages for every uploaded image, and filtered product listings. Decide deliberately which of these deserve to be indexed. In WordPress, attachment pages should redirect to the file or parent post. Single-post tag archives are usually better as noindex, follow until they grow. ## URL structure and redirect mapping Good URLs are short, lowercase, hyphen-separated, readable and stable. Decide the structure during planning, because changing it after launch means another round of redirects. Avoid dates in evergreen content URLs, file extensions you might drop later, and deep folder hierarchies that mirror your internal org chart instead of how users think. ### The redirect map for a redesign If the new site replaces an existing one, the redirect map is the single most important SEO deliverable of the project. The process: - **Inventory the old URLs.** Combine a full crawl, the old XML sitemap, analytics landing pages and Search Console's top pages. URLs with backlinks matter most. - **Map each old URL to its closest new equivalent.** Map one to one where you can. Don't redirect everything to the homepage. Search engines tend to treat mass homepage redirects as soft 404s. - **Implement the redirects as single-hop 301s** at the server or with a redirect plugin. Avoid chains like old → interim → new. - **Test before DNS changes**, using a script that requests every old URL and checks for one 301 that lands on a 200. - **Keep the redirects in place long term.** Google's site-move guidance recommends keeping them for at least a year, and in practice there is rarely a reason to remove them at all. ``` # Quick redirect check: each line of old-urls.txt is a full URL while read -r url; do result=$(curl -s -o /dev/null -w "%{http_code} %{num_redirects} %{url_effective}" -L "$url") echo "$url -> $result" done < old-urls.txt ``` Any line that shows more than one redirect, or a final status other than 200, needs fixing before launch. ## On-page technical elements ### Titles, descriptions and headings - **Unique on every page**, leading with the page's subject. Search engines may rewrite titles that are vague, stuffed with keywords or duplicated. - **Meta descriptions** don't directly affect rankings, but they are often used as the snippet. Write them as a short pitch for the page. - **One clear <h1>** per page and a logical <h2>/<h3> hierarchy. Headings describe structure, so don't use them for styling. - **lang attribute** on the <html> element, and hreflang annotations if you publish multiple language or regional versions. ### Structured data Structured data (JSON-LD using the schema.org vocabulary) helps search engines understand what a page represents and makes it eligible for certain rich results. For a typical business site, start with Organization or LocalBusiness on the homepage, BreadcrumbList sitewide, Article on blog posts and Product on shop pages. The markup must describe content that is actually visible on the page. ``` <script type="application/ld+json"> { "@context": "https://schema.org", "@type": "Organization", "name": "Example Studio", "url": "https://www.example.com/", "logo": "https://www.example.com/logo.png", "sameAs": [ "https://www.linkedin.com/company/example-studio", "https://github.com/example-studio" ] } </script> ``` Validate markup with Google's Rich Results Test and the Schema Markup Validator before launch. Structured data also helps AI-driven search experiences identify your brand, which we cover in our guide to [generative engine optimization](/blog/generative-engine-optimization-ai-search/). ### XML sitemaps Your sitemap should list only canonical, indexable URLs that return 200: no redirects, no noindex pages, no parameter variants. Google's [sitemap documentation](https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap) sets the limits at 50,000 URLs or 50 MB uncompressed per file. It also states that <priority> and <changefreq> are ignored, and that <lastmod> is used only when it is consistently accurate. Let your CMS generate the sitemap, then audit what it includes. ## Performance, mobile and security ### Core Web Vitals Page experience isn't a magic ranking lever, but slow, unstable pages lose visitors whatever their position. Google assesses Core Web Vitals at the 75th percentile of real-user visits, with these "good" thresholds: | | Metric | Measures | Good | Poor | Common launch culprits | LCP (Largest Contentful Paint) | Loading of the main content | ≤ 2.5 s | > 4.0 s | Unoptimised hero images, slow server response, render-blocking CSS | INP (Interaction to Next Paint) | Responsiveness to input | ≤ 200 ms | > 500 ms | Heavy third-party scripts, large JavaScript bundles, long tasks | CLS (Cumulative Layout Shift) | Visual stability | ≤ 0.1 | > 0.25 | Images without dimensions, late-loading banners, web font swaps A brand-new site has no field data yet, so use lab tools (Lighthouse, WebPageTest) on representative templates before launch: the homepage, a service page, a blog post and a product page. Then watch the field data as it builds up. Our [Core Web Vitals guide](/blog/core-web-vitals-guide/) goes deeper on fixing each metric. Server response time also depends heavily on your platform, which we compare in [choosing web hosting](/blog/choosing-web-hosting-static-wordpress-vps/). ### Mobile-first indexing Google primarily crawls and indexes with a smartphone user agent. The mobile version of a page is the version that gets indexed. Make sure content, structured data, internal links and meta tags are identical across breakpoints. Don't hide text in mobile layouts that you want to rank for. ### HTTPS and security headers - A valid certificate covering every hostname you serve, with automatic renewal. - No mixed content. Every image, script and font loads over HTTPS. - A Strict-Transport-Security (HSTS) header once you are sure HTTPS works everywhere. - Sensible defaults for X-Content-Type-Options, Referrer-Policy and a Content Security Policy where practical. ## The launch-day checklist Use this table on the day the site goes live. Every row should be verified on the production domain, not on staging. | | Check | How to verify | Pass condition | Indexing allowed | View source and response headers on key templates | No noindex meta tag or X-Robots-Tag header | robots.txt | Open /robots.txt | No blanket Disallow: /, sitemap URL listed | Canonical host | Request http, non-www and trailing-slash variants | Single 301 to the preferred URL | Canonical tags | Crawl the site | Absolute, self-referencing, production domain only | Redirect map | Run the redirect script against old URLs | One hop, final status 200 | Sitemap | Crawl the sitemap URLs | All 200, all indexable, all canonical | Structured data | Rich Results Test on each template | No errors; markup matches visible content | Performance | Lighthouse on mobile for each template | LCP, CLS and total blocking time within budget | HTTPS | Browser console and a crawl | No mixed content or certificate warnings | Custom 404 | Request a made-up URL | Helpful page served with a 404 status ## The first 30 days after launch ### Set up Search Console and Bing Webmaster Tools Verify the domain property in Google Search Console (DNS verification covers every protocol and subdomain), submit the sitemap, and do the same in Bing Webmaster Tools. Bing's index also feeds several other search and AI products, so it is worth the ten minutes. Use the URL Inspection tool on your most important pages to request indexing and confirm that Google sees the rendered content you expect. ### Watch the reports, not the rankings In the first weeks, rankings move around too much to tell you much. These signals are more useful: - **Page indexing report:** look for "Crawled – currently not indexed", "Duplicate without user-selected canonical" and unexpected exclusions. - **Crawl stats and server logs:** confirm that Googlebot gets fast 200 responses, not timeouts or 5xx errors. - **404s from old URLs:** every one is a missed redirect. Add it to the map. - **Core Web Vitals report:** fills in once enough real-user data exists. **Key takeaways** - Protect staging with authentication, and keep a written list of every setting that must change at launch. - Consolidate to one canonical host, use self-referencing canonical tags, and keep your sitemap limited to clean 200 URLs. - For redesigns, the one-to-one redirect map matters more than anything else on this list. - Verify everything on production on launch day, then monitor Search Console's indexing reports for the first month. ## Launch once, launch clean Technical SEO isn't glamorous, and done well it is invisible: pages get found, the right URLs get indexed, and your content competes on its merits. Most of the items above are cheap to get right during the build and expensive to fix after launch, which is why we fold them into the plan from day one. If you are still at that stage, our guide to [planning a website project](/blog/website-project-planning-guide/) shows where SEO fits into scope and timeline. Launching soon, or worried that a recent launch or redesign went wrong? Our [Performance & Technical SEO Audit](/service/performance-seo-audit/) works through this checklist and more, and gives you a prioritised list of fixes in plain language. [Get in touch](/contact-us/) and tell us about your site, and we'll tell you honestly what it needs. ## FAQ **Q:** When should technical SEO start on a new website project? **A:** During planning, not the week before launch. URL structure, the CMS, hosting and the redirect map from any old site all affect SEO and are expensive to change later. Treat the checklist as part of the build, then verify it again on launch day. **Q:** Should I block my staging site with robots.txt? **A:** Robots.txt only asks crawlers not to fetch pages; it does not reliably keep URLs out of the index if they are linked from elsewhere. Password protection (HTTP authentication) is the safest way to keep a staging site private, with a noindex header as a second layer. **Q:** How long does it take for a new website to appear in Google? **A:** There is no fixed timeline. A new site with a submitted sitemap and a few links pointing to it is often discovered within days, but indexing every page and building rankings takes considerably longer. Search Console's URL Inspection tool shows you exactly what Google knows about any URL. **Q:** Do sitemap priority and changefreq values matter? **A:** Not for Google. Google's documentation states that it ignores priority and changefreq, and it uses lastmod only when the dates are consistently accurate. Spend your effort on keeping the sitemap clean: only canonical, indexable URLs that return a 200 status. --- # WCAG 2.2 for Small Businesses: A Practical Accessibility Guide URL: https://hiddlins.com/blog/wcag-accessibility-guide-small-business/ Published: 2026-08-23 · Updated: 2026-08-23 Web accessibility used to be treated as a specialist concern for governments and large enterprises. That has changed. WCAG 2.2, published by the W3C in October 2023, is now the reference point for accessible websites, and the European Accessibility Act has applied since June 28, 2025, bringing accessibility requirements to many businesses that sell to consumers in the EU — including online shops. For a small business, the good news is that most of the work is not exotic. It is a set of sound design and development habits that also make your site easier for everyone to use. This guide explains what WCAG 2.2 asks for, what is new, where the law stands and which fixes deliver the most value for the least effort. ## Why accessibility matters for a small business Disability is common. People with visual, hearing, motor and cognitive impairments use the web every day with screen readers, magnifiers, voice control, switch devices or just the keyboard. Many more experience temporary or situational limitations: a broken wrist, a phone in bright sunlight, a noisy train, a slow connection or simply aging eyes. When your site works for them, it works better for everyone. There are also direct business reasons: - **More customers.** Every form a keyboard user cannot complete or a checkout a screen reader user cannot navigate is lost revenue that never shows up in your analytics. - **Legal risk.** Accessibility is now a legal requirement in more places and for more types of business than ever, as we explain below. - **Better SEO and UX.** Clear headings, descriptive links, text alternatives and semantic markup help search engines and AI systems understand your pages. Our article on [semantic HTML](/blog/semantic-html-seo-accessibility/) shows how much of this overlap is free. - **Lower maintenance cost.** Accessible components built once into a design system are cheaper than retrofitting every page later. ## WCAG 2.2 in five minutes The [Web Content Accessibility Guidelines (WCAG) 2.2](https://www.w3.org/TR/WCAG22/) are organized around four principles, often remembered as **POUR**: - **Perceivable** — information can be perceived in more than one way: text alternatives for images, captions for video, sufficient contrast. - **Operable** — everything can be operated with a keyboard and other input methods, with enough time and without triggering seizures. - **Understandable** — content and interfaces are predictable, readable and help users avoid and correct mistakes. - **Robust** — content works reliably with current and future assistive technologies, mainly through correct semantics. Under these principles sit testable **success criteria**, each assigned a level: A (minimum), AA (the standard target) and AAA (enhanced). When laws and contracts reference WCAG, they almost always mean **Level AA**, which includes all A and AA criteria. WCAG versions are backwards compatible: a site that meets 2.2 AA also meets 2.1 AA and 2.0 AA. The one exception to "2.2 only adds" is that 4.1.1 Parsing was removed as obsolete, because modern browsers and assistive technologies no longer depend on it. ## What is new in WCAG 2.2 WCAG 2.2 added nine success criteria, summarized in the W3C's [What's New in WCAG 2.2](https://www.w3.org/WAI/standards-guidelines/wcag/new-in-22/) overview. Six of them are at Level A or AA and therefore part of a normal compliance target: | | Criterion | Level | What it means in practice | 2.4.11 Focus Not Obscured (Minimum) | AA | A focused element must not be completely hidden by sticky headers, cookie banners or chat widgets. | 2.4.12 Focus Not Obscured (Enhanced) | AAA | No part of the focused element is hidden. | 2.4.13 Focus Appearance | AAA | Focus indicators meet minimum size and contrast requirements. | 2.5.7 Dragging Movements | AA | Anything done by dragging can also be done with simple clicks or taps. | 2.5.8 Target Size (Minimum) | AA | Clickable targets are at least 24 × 24 CSS pixels, or spaced so they do not crowd each other, with some exceptions. | 3.2.6 Consistent Help | A | Help options such as contact details or chat appear in the same relative place across pages. | 3.3.7 Redundant Entry | A | Do not make people re-type information they already gave in the same process. | 3.3.8 Accessible Authentication (Minimum) | AA | Logging in must not depend on memorizing, transcribing or solving puzzles, unless help or an alternative is provided. | 3.3.9 Accessible Authentication (Enhanced) | AAA | As above, without the object and personal content recognition exceptions. ### 2.4.11 Focus Not Obscured (Minimum) Keyboard users need to see where they are. Sticky headers are the usual culprit: when someone tabs to a link near the top of the viewport, the browser scrolls it into view directly beneath the header. CSS has a simple fix — tell the browser how much space the sticky header occupies: ``` html { scroll-padding-top: 5rem; /* at least the height of the sticky header */ } :focus-visible { outline: 3px solid #1d4ed8; outline-offset: 2px; } ``` Cookie consent banners and chat bubbles that permanently cover part of the page need the same attention: make sure they can be dismissed and do not sit over focusable content. ### 2.5.7 Dragging Movements Sliders, sortable lists, kanban boards and map panning often rely on dragging, which is difficult or impossible for many people with motor impairments and for some assistive technology users. Provide a single-pointer alternative: plus and minus buttons beside a range slider, "Move up" and "Move down" buttons on sortable items, or a text input for a value. This is about pointer alternatives; keyboard operability is covered separately by 2.1.1 Keyboard. ### 2.5.8 Target Size (Minimum) Interactive targets must be at least 24 by 24 CSS pixels, unless they are spaced so that a 24-pixel circle centered on each does not overlap another target, the same function is available elsewhere, the target is a link inside a sentence, the size is controlled by the browser, or a particular presentation is essential. Small icon buttons, close buttons on pop-ups and tightly packed pagination links are typical failures. The minimum is a floor; for touch interfaces, larger targets around 44 pixels are kinder, as we discuss in our article on [UX principles that move conversion rates](/blog/ux-principles-conversion/). ### 3.2.6 Consistent Help If you offer help — a phone number, contact link, chat widget or FAQ link — on multiple pages, keep it in the same relative order on each page. People who rely on predictability should not have to hunt for help on every new screen. ## The legal landscape in 2026 **This is not legal advice** - Accessibility law varies by country and by type of organization. Use this section as orientation and confirm your obligations with a qualified legal professional. ### The European Accessibility Act The European Accessibility Act, [Directive (EU) 2019/882](https://eur-lex.europa.eu/eli/dir/2019/882/oj), has applied since June 28, 2025. It sets accessibility requirements for a range of products and services offered to consumers in the EU, including e-commerce services, consumer banking, e-books, electronic communications and parts of passenger transport such as ticketing. It is implemented through national laws in each member state, which also set enforcement mechanisms and penalties. Key points for small businesses: - **Location does not exempt you.** A business based outside the EU that sells covered services to EU consumers can fall within scope. - **Microenterprises providing services are exempt.** A microenterprise is defined as having fewer than 10 employees and an annual turnover or balance sheet total of no more than 2 million euros. The exemption covers services, not products. - **WCAG is the practical benchmark.** Compliance is generally demonstrated through the harmonized European standard EN 301 549, whose web requirements are aligned with WCAG at Level AA. - **An accessibility statement is expected.** Service providers must provide information about how their service meets the requirements. ### Elsewhere In the United States, courts have repeatedly treated business websites as subject to the Americans with Disabilities Act, and in 2024 the Department of Justice adopted WCAG 2.1 AA as the technical standard for state and local government websites under Title II. The UK's Equality Act 2010 requires service providers to make reasonable adjustments for disabled people. Across all of these, WCAG Level AA is the common technical reference, which is why building to WCAG 2.2 AA is the most future-proof choice. ## The fixes with the biggest impact You do not need to memorize every success criterion to make a dramatic difference. These issues account for a large share of real-world barriers, and most are cheap to fix. ### Text alternatives Every meaningful image needs alt text that conveys its purpose in context; decorative images need an empty alt="" so screen readers skip them. Product images should describe what matters to a buyer ("Navy wool overcoat, knee length, with notched lapels"), not "image1.jpg" or "product photo". Charts need a text summary of the insight and access to the data. ### Color contrast Body text needs a contrast ratio of at least 4.5:1 against its background; large text (at least 18 point, or 14 point bold — roughly 24 and 18.5 CSS pixels) needs 3:1. Under 1.4.11 Non-text Contrast, icons, input borders, focus indicators and chart elements need 3:1 against adjacent colors. Never use color as the only way to convey meaning, such as red borders alone for errors. ### Keyboard access and visible focus Unplug your mouse and try to use your site. Every link, button, menu, form control and dialog must be reachable with Tab, operable with Enter or Space, and must show a clearly visible focus indicator. The usual offenders are custom dropdowns built from div elements, mega-menus that only open on hover, modals that do not trap or return focus, and outline: none in a theme's CSS. Native elements such as <button>, <a href> and <select> give you keyboard support for free. ### Structure: headings, landmarks and links Screen reader users frequently navigate by headings and landmarks. Use one logical heading hierarchy, wrap regions in <header>, <nav>, <main> and <footer>, and write link text that makes sense out of context — "Download the 2026 price list (PDF)" rather than "click here". ### Zoom, reflow and motion Content must remain usable when text is enlarged to 200% and must reflow without horizontal scrolling at a width equivalent to 320 CSS pixels, which is what a 1280-pixel-wide window looks like at 400% zoom. Respect prefers-reduced-motion, and give users a way to pause moving content that runs for more than five seconds. Our [Canvas particle animation tutorial](/blog/canvas-particle-animation-tutorial/) shows how to build a decorative animation that does exactly that. ### Video and audio Pre-recorded video with speech needs accurate captions (auto-generated captions are a starting point, not a finished product), and audio-only content such as podcasts needs a transcript. ## Forms, checkouts and logins Forms are where accessibility failures cost the most, because they block the actions that matter: enquiries, purchases and sign-ins. Three WCAG 2.2 criteria and several older ones meet here. ### Labels, instructions and errors Every input needs a visible, programmatically associated label. Errors must be identified in text, linked to the field and explain how to fix the problem: ``` <label for="email">Email address</label> <input id="email" name="email" type="email" autocomplete="email" aria-invalid="true" aria-describedby="email-error"> <p id="email-error" class="field-error"> Enter an email address in the format name@example.com </p> ``` On submit, move focus to the first invalid field or to an error summary at the top of the form, and announce dynamic messages such as "Added to cart" with a live region so screen reader users know something happened. ### 3.3.7 Redundant Entry If a customer has already entered their shipping address, do not make them type it again as a billing address — offer a "Billing address is the same as shipping" checkbox or pre-fill the fields. The criterion allows exceptions where re-entry is essential, such as confirming a new password, where it is needed for security, or where the earlier information is no longer valid. ### 3.3.8 Accessible Authentication (Minimum) Remembering a password or transcribing a code is a cognitive function test. Logging in must not depend on one unless there is an alternative or a mechanism to help. In practice that means: - **Never block paste** in password or verification code fields, and use the correct autocomplete values (username, current-password, new-password, one-time-code) so password managers and browsers can fill them. - **Offer alternatives** such as email magic links, passkeys or sign-in with an existing account. - **Be careful with CAPTCHAs.** At Level AA, tests based on recognizing objects or on content the user provided are permitted, but puzzles, distorted text and arithmetic challenges are not acceptable without an alternative. Invisible, risk-based bot protection avoids the problem altogether. ``` <label for="password">Password</label> <input id="password" name="password" type="password" autocomplete="current-password"> <!-- No onpaste="return false", no "retype your password" field on login --> ``` On WordPress and WooCommerce, check that security plugins and checkout customizations do not quietly break these rules — our [WordPress security hardening checklist](/blog/wordpress-security-hardening/) shows how to strengthen logins without making them harder to use. ## How to test without an expensive audit A formal audit by accessibility specialists is valuable for complex sites and high-risk services, but you can find and fix the majority of serious issues yourself with a short, repeatable routine. - **Automated scan.** Run a browser extension such as axe DevTools or WAVE, or the accessibility section of Lighthouse, on your key templates: home, category, product, cart, checkout, contact and a blog post. Fix everything they flag, but remember they detect only some failures. - **Keyboard pass.** Complete your most important journey — enquiry, purchase or sign-up — using only the keyboard. Note anything you cannot reach, cannot see focus on or cannot escape. - **Zoom and reflow.** Zoom to 200% and 400% in a desktop browser and confirm nothing is cut off, overlapping or requiring sideways scrolling. - **Screen reader spot check.** Use VoiceOver on macOS or iOS, or the free NVDA on Windows. Navigate by headings, list the links and complete a form. Listen for unlabeled buttons and confusing announcements. - **Content review.** Check alt text quality, link wording, heading order, captions and plain language. No tool can judge whether an alt text is actually helpful. **Make it a habit** - Test each new template or component before launch rather than the whole site once a year. - Add an accessibility check to your definition of done for content updates. - Keep a simple log of known issues and planned fixes; it doubles as the basis of your accessibility statement. ## Why overlays are not a shortcut Accessibility overlay widgets promise one-line compliance by adding a toolbar or automatically "fixing" pages with JavaScript. They are tempting for a small business, but they cannot repair the underlying problems: they cannot write meaningful alt text, restructure a confusing checkout, make a custom widget keyboard-operable or caption your videos. Many disabled users report that overlays interfere with the screen readers and settings they already rely on, and installing one does not shield a business from complaints or legal claims. The budget is better spent fixing your templates, which permanently improves every page built on them. ## Making accessibility stick Accessibility is a process, not a project. The businesses that stay accessible build it into how they work: - **Accessible components first.** Buttons, form fields, menus, modals and tabs built once, correctly, and reused everywhere. - **Editor guidance.** A one-page guide for whoever adds content: how to write alt text, use headings, name links and caption video. - **An accessibility statement.** Describe the standard you aim for, known limitations and how people can report problems or get information in another format, as we do on our own [accessibility statement](/accessibility-statement/). - **A feedback route that works.** An email address or form that someone actually monitors, with a commitment to respond. - **Accessible data and media.** Charts with text summaries and data tables, as covered in our guide to [data visualization on the web](/blog/web-data-visualization-svg-canvas-webgl/). **Key takeaways** - Target WCAG 2.2 Level AA; it is the benchmark behind most laws and standards. - The European Accessibility Act has applied since June 28, 2025, and can cover non-EU businesses selling to EU consumers; service microenterprises are exempt. - The new 2.2 criteria focus on visible focus, dragging alternatives, target size, consistent help, redundant entry and accessible logins. - Contrast, keyboard access, labels, alt text and structure fix the majority of real-world barriers. - Combine automated scans with keyboard, zoom and screen reader checks; overlays are not a substitute. ## Start where your customers act If accessibility feels overwhelming, start with the journeys that matter most to your business — the contact form, the product page, the checkout, the login — and make them work by keyboard, at high zoom and with a screen reader. Then build those fixes into your templates so every future page inherits them. Progress beats perfection. Accessibility is part of how we design and build, not an afterthought bolted on at the end. If you are planning a new site, our [WordPress Website Development](/service/wordpress-website-development/) service includes accessible templates and editor guidance, and our [Website Care & Maintenance Plan](/service/website-care-maintenance-plan/) keeps an eye on accessibility as your content evolves. [Contact us](/contact-us/) to talk through where your site stands today. ## FAQ **Q:** Which WCAG level should a small business website aim for? **A:** Aim for WCAG 2.2 Level AA. It is the level referenced by most laws, procurement rules and standards, including EN 301 549 in Europe, and it covers the issues that most affect real users. Level AAA is not expected for entire sites, although individual AAA criteria are worth adopting where practical. **Q:** Does the European Accessibility Act apply to my business? **A:** It can apply to businesses inside or outside the EU that offer covered products or services, such as e-commerce, to consumers in the EU. Microenterprises providing services, meaning fewer than 10 employees and no more than 2 million euros in annual turnover or balance sheet total, are exempt from the service requirements. Check your specific situation with a legal professional. **Q:** Can an accessibility overlay or plugin make my site compliant? **A:** No tool can make an inaccessible site compliant on its own. Overlays cannot reliably fix missing labels, poor structure, keyboard traps or inaccessible checkouts, and many disabled users find they interfere with the assistive technology they already use. Fixing the underlying code and content is the only dependable route. **Q:** How much of accessibility testing can be automated? **A:** Automated checkers are valuable for catching issues like missing alternative text, low contrast and missing form labels, but they can only detect a portion of WCAG failures. Keyboard testing, zoom and reflow checks, screen reader spot checks and human judgment about content quality are still required. **Q:** What changed between WCAG 2.1 and WCAG 2.2? **A:** WCAG 2.2 added nine success criteria, covering focus visibility, dragging alternatives, minimum target size, consistent help, redundant entry and accessible authentication, and removed the obsolete 4.1.1 Parsing criterion. Content that meets WCAG 2.2 also meets WCAG 2.1 and 2.0. --- # Building a Lightweight Canvas Particle Animation from Scratch URL: https://hiddlins.com/blog/canvas-particle-animation-tutorial/ Published: 2026-08-13 · Updated: 2026-08-13 A soft field of drifting dust behind a hero headline adds depth and atmosphere without shouting for attention — the effect you see at the top of our own site works exactly this way. You do not need a library, sprite sheets or WebGL to build one. With the Canvas 2D API, around 150 lines of plain JavaScript and a little physics, you can create a particle system that looks smooth on any refresh rate, stays sharp on high-density screens, resizes gracefully, costs very little CPU and switches itself off for people who prefer reduced motion. This tutorial builds it step by step and explains every decision along the way. ## What we are building, and why sprite-free Our particle system draws each particle directly as a small filled circle (or a tiny square when it is too small for the difference to be visible). There are no image sprites to download, decode or tint, which keeps the effect at zero extra network requests and lets us change color, size and opacity freely per particle. The feature list: - A loop driven by requestAnimationFrame with **delta time**, so motion is identical at 60 Hz and 144 Hz. - Simple, stable physics: a **spring** toward a slowly rising anchor, random **jitter** and frame-rate independent **drag**. - A **depth** value per particle that controls size, opacity and speed for a parallax feel. - **Respawning** with fade-in and fade-out, so particles never pop in or out and no objects are created after start-up. - Sharp rendering with **devicePixelRatio**, **resize handling** with ResizeObserver, and pausing when off-screen. - Full respect for **prefers-reduced-motion**. If you are still deciding whether Canvas is the right renderer at all, our comparison of [SVG, Canvas and WebGL](/blog/web-data-visualization-svg-canvas-webgl/) explains the trade-offs. For a few hundred small moving dots, Canvas 2D is the sweet spot. ## Setting up the canvas ### Markup and CSS The canvas is purely decorative, so it is hidden from assistive technology and ignores pointer events so it never blocks clicks on the content above it: ``` <section class="hero"> <canvas class="hero-dust" aria-hidden="true"></canvas> <div class="hero-content"> <h1>Your headline</h1> </div> </section> ``` ``` .hero { position: relative; isolation: isolate; /* keeps the negative z-index inside the hero */ } .hero-dust { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; } ``` Because the canvas is absolutely positioned and sized by CSS, it can never cause layout shift, and the hero text remains the Largest Contentful Paint element. ### Configuration and state Keep every tunable number in one object. It makes the effect easy to art-direct and documents the units of each value: ``` const canvas = document.querySelector('.hero-dust'); const ctx = canvas.getContext('2d'); const CONFIG = { density: 1 / 9000, // particles per CSS pixel² of canvas area minCount: 24, maxCount: 220, maxDpr: 2, // cap the backing-store resolution minRadius: 0.6, // CSS px at depth 0 (far) maxRadius: 2.4, // CSS px at depth 1 (near) rise: 14, // px/s upward anchor drift for the nearest layer spring: 0.9, // spring stiffness toward the anchor, 1/s² drag: 1.6, // velocity damping rate, 1/s jitter: 22, // random kick strength, px/s per √s color: '255, 236, 210' }; const particles = []; const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); let width = 0, height = 0, dpr = 1; let running = false, visible = true, rafId = 0, last = 0; ``` ### Sharp pixels with devicePixelRatio A canvas has a CSS size and a separate bitmap size. On a screen with a [devicePixelRatio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) of 2 or 3, a bitmap that matches the CSS size gets stretched and looks blurry. We size the bitmap in device pixels, then apply a transform so all drawing code can keep working in CSS pixels. We cap the ratio at 2: on a 3× phone the difference for soft dust is invisible, but the pixel count — and the fill cost — would be 2.25 times higher. ``` function resize() { const rect = canvas.getBoundingClientRect(); width = Math.max(1, rect.width); height = Math.max(1, rect.height); dpr = Math.min(window.devicePixelRatio || 1, CONFIG.maxDpr); canvas.width = Math.round(width * dpr); // resets all context state… canvas.height = Math.round(height * dpr); ctx.setTransform(dpr, 0, 0, dpr, 0, 0); // …so re-apply the transform after syncCount(); if (!running) draw(); // keep the static frame correct when paused } function syncCount() { const target = Math.round(Math.min(CONFIG.maxCount, Math.max(CONFIG.minCount, width * height * CONFIG.density))); while (particles.length < target) particles.push(spawn({}, true)); particles.length = target; // truncates when the canvas shrinks } ``` Scaling the particle count with the area keeps the visual density consistent from a phone to an ultrawide monitor, while the cap protects large screens from doing unnecessary work. ## The particle model Each particle is a small plain object with a position, velocity, an anchor that a spring pulls it toward, a depth value z between 0 (far) and 1 (near), and an age and lifetime in seconds: ``` function spawn(p, initial = false) { p.z = Math.random() ** 1.5; // biased toward small, distant dust p.x = p.ax = Math.random() * width; p.y = p.ay = Math.random() * height; p.vx = p.vy = 0; p.life = 6 + Math.random() * 8; // seconds p.age = initial ? Math.random() * p.life : 0; return p; } ``` Two details matter. First, raising Math.random() to the power of 1.5 skews the distribution toward 0, so there are more small, faint, distant particles than large, bright, near ones — which is how real depth looks. Second, the very first batch starts at random ages, so particles do not all fade in together and then die together in a synchronized pulse. spawn() takes an existing object and reinitializes it rather than creating a new one. After start-up, the animation allocates nothing, so the garbage collector has nothing to clean up and never causes a mid-animation hitch. For very large systems you could go further and store fields in typed arrays (a "structure of arrays"), but for a few hundred particles plain objects are perfectly fast and far more readable. ## The animation loop and delta time [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame) calls your function just before the browser paints, passing a high-resolution timestamp. It runs at the display's refresh rate and is paused automatically in background tabs, which is why it is the right tool instead of setInterval. ``` function frame(now) { // Seconds since the previous frame, clamped to a safe range. const dt = Math.min(Math.max((now - last) / 1000, 0), 0.05); last = now; update(dt); draw(); rafId = requestAnimationFrame(frame); } function start() { if (running || reducedMotion.matches || !visible) return; running = true; last = performance.now(); rafId = requestAnimationFrame(frame); } function stop() { running = false; cancelAnimationFrame(rafId); } ``` ### Why delta time Refresh rates vary between 60, 90, 120, 144 Hz and more, and any device drops frames under load. If you move a particle "two pixels per frame", it moves twice as fast on a 120 Hz screen and stutters whenever a frame is skipped. Expressing every velocity in pixels per second and multiplying by dt makes motion depend on real time, not on frame count. ### Why clamp it When the tab regains focus after a minute in the background, the next timestamp could be 60 seconds after the previous one. Without a clamp, every particle would leap across the screen in one step and the spring could even become numerically unstable. Capping dt at 50 ms means a long pause simply resumes smoothly. The lower clamp of 0 guards against the first callback's timestamp being marginally earlier than the performance.now() value we recorded in start(). ## Physics: spring, jitter and drag We use semi-implicit Euler integration: update velocity from forces first, then update position from the new velocity. It is simple, cheap and stable for small, damped systems like this one. ``` function update(dt) { const { rise, spring, jitter } = CONFIG; const damping = Math.exp(-CONFIG.drag * dt); // frame-rate independent drag const kick = jitter * Math.sqrt(dt); // random-walk scaling for (const p of particles) { const depth = 0.35 + 0.65 * p.z; // near particles move more p.ay -= rise * depth * dt; // the anchor drifts upwards p.vx += (p.ax - p.x) * spring * dt; // spring toward the anchor p.vy += (p.ay - p.y) * spring * dt; p.vx += (Math.random() * 2 - 1) * kick * depth; // jitter p.vy += (Math.random() * 2 - 1) * kick * depth; p.vx *= damping; // drag p.vy *= damping; p.x += p.vx * dt; p.y += p.vy * dt; p.age += dt; if (p.age >= p.life || p.y < -20 || p.x < -20 || p.x > width + 20) { spawn(p); } } } ``` ### The spring Each particle is attached to an invisible anchor by a spring: the further it wanders, the harder it is pulled back (Hooke's law, force proportional to distance). Moving the anchor slowly upwards produces a gentle rising drift, while the spring keeps the particle loosely following it rather than traveling in a perfectly straight line. ### Jitter as a random walk Jitter adds a small random kick every frame, which is what makes dust look like it is floating in moving air. Notice the kick is scaled by Math.sqrt(dt), not dt. Random kicks partially cancel out, so their combined effect grows with the square root of the number of steps. Scaling by the square root of the time step keeps the amount of wandering consistent whether you run 60 or 144 frames per second; scaling by dt would make the effect visibly calmer on fast displays. ### Frame-rate independent drag A common mistake is v *= 0.98 every frame, which is frame-rate dependent: at 120 Hz the velocity decays twice as often. Exponential decay, v *= Math.exp(-drag * dt), removes the same fraction of velocity per second at any frame rate. With the defaults above, drag and spring form a slightly under-damped system, so particles sway softly instead of oscillating forever or snapping rigidly to their anchors. | | Setting | Increase it to… | Too high looks like… | rise | Make the dust drift upwards faster | Rain falling in reverse | spring | Keep particles closer to their path | Stiff, wobbling motion | drag | Calm the motion, kill overshoot | Particles that feel stuck in syrup | jitter | Add turbulence and liveliness | Buzzing insects | density | Add more particles per area | Visual noise competing with the text | maxRadius | Make near particles bigger | Bokeh blobs rather than dust ## Depth: scale, alpha and parallax A single depth value per particle produces a convincing sense of three dimensions without any 3D maths. Near particles (high z) are larger, more opaque and move more; far particles are tiny, faint and slow. In update() the depth factor already scales both the rise speed and the jitter. Drawing applies the same idea to size and opacity, multiplied by a lifetime fade: ``` function draw() { ctx.clearRect(0, 0, width, height); ctx.fillStyle = `rgb(${CONFIG.color})`; const span = CONFIG.maxRadius - CONFIG.minRadius; for (const p of particles) { const fade = Math.sin(Math.PI * (p.age / p.life)); // 0 → 1 → 0 ctx.globalAlpha = (0.15 + 0.55 * p.z) * fade; const r = CONFIG.minRadius + span * p.z; if (r < 1) { ctx.fillRect(p.x - r, p.y - r, r * 2, r * 2); // tiny: a square is cheaper } else { ctx.beginPath(); ctx.arc(p.x, p.y, r, 0, Math.PI * 2); ctx.fill(); } } ctx.globalAlpha = 1; } ``` Because the particles are small and translucent, draw order barely matters, so we skip depth sorting entirely. If you increase the maximum radius and notice near particles being drawn behind far ones, sort the array by z after spawning instead of every frame. ### Batching for larger counts Each arc() plus fill() is a separate draw operation. If you push into the high hundreds, quantize opacity into, say, eight buckets and draw each bucket as a single path with one fill(). You trade a tiny amount of opacity precision for far fewer state changes — the same batching principle that makes Canvas charts fast. ## Lifecycle and respawning A particle is recycled when it reaches the end of its lifetime or drifts beyond a small margin outside the canvas. Recycling simply calls spawn(p) on the same object with initial set to false, so its age restarts at zero. The lifetime fade, Math.sin(Math.PI * t) where t runs from 0 to 1, is what makes recycling invisible: opacity is zero at birth, peaks halfway and returns to zero at death. A particle is therefore never visible at the moment it teleports to a new position. The out-of-bounds check is a safety net for particles that wander off the edge before their fade completes, and the 20-pixel margin ensures that even the largest particle is fully off-canvas when that happens. Randomizing the lifetime between 6 and 14 seconds, combined with random starting ages, keeps births and deaths evenly spread so the overall density stays constant and the field never "breathes" in unison. ## Reduced motion, visibility and performance ### Honor prefers-reduced-motion Some people experience nausea, dizziness or distraction from motion on screen and ask their operating system to reduce it. The [prefers-reduced-motion](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@media/prefers-reduced-motion) media feature exposes that preference. Our start() function already refuses to run when it matches; in that case resize() draws a single, still frame, so the hero keeps its texture without any movement. We also react if the setting changes while the page is open. (Our [WCAG 2.2 guide](/blog/wcag-accessibility-guide-small-business/) covers the related success criteria.) ``` reducedMotion.addEventListener('change', () => { if (reducedMotion.matches) { stop(); draw(); } else { start(); } }); // Pause when the hero scrolls out of view. new IntersectionObserver(([entry]) => { visible = entry.isIntersecting; if (visible) start(); else stop(); }).observe(canvas); // Resize with the element, not just the window. new ResizeObserver(resize).observe(canvas); // Re-render when devicePixelRatio changes (zoom, moving between monitors). function watchDpr() { window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`) .addEventListener('change', () => { resize(); watchDpr(); }, { once: true }); } resize(); watchDpr(); start(); ``` A [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) on the canvas is better than a window resize listener because the hero can change size without the window changing — for example when fonts load, content wraps differently or a banner is dismissed. It also fires once on observe, so the canvas is sized correctly from the start. **Reduced motion is necessary, not sufficient** - WCAG 2.2.2 Pause, Stop, Hide (Level A) asks for a way to pause moving content that starts automatically, lasts more than five seconds and appears alongside other content. - Many people who are bothered by motion never change their OS setting, so a small, keyboard-accessible pause button is the safest choice for anything more than a barely perceptible effect. - Keep the effect low in contrast so it never reduces the legibility of text placed on top of it. ### Keep the main thread free Everything in this effect runs on the main thread, which also handles clicks and typing. Keep per-frame work tiny — our loop is a few hundred multiplications and draw calls — and profile on a low-end phone using the browser's Performance panel. Pausing when off-screen means visitors reading further down the page pay nothing at all. Our [Core Web Vitals guide](/blog/core-web-vitals-guide/) explains why main-thread time matters for Interaction to Next Paint, and if you need a much heavier effect, rendering inside a worker with OffscreenCanvas takes it off the main thread entirely. **Key takeaways** - Use requestAnimationFrame and express all motion per second, multiplied by a clamped delta time. - Exponential drag and square-root-scaled jitter keep the look identical at every refresh rate. - One depth value can drive size, opacity and speed for convincing parallax. - Recycle particles with a sine fade to avoid allocations and visible popping. - Scale the bitmap by a capped devicePixelRatio, resize with ResizeObserver, pause off-screen and honor reduced motion. ## Small code, big atmosphere This effect shows how far the web platform goes on its own. There is no framework and no build step required, and the whole thing is small enough to read in one sitting. That is the spirit of our article on [modern JavaScript without the bloat](/blog/vanilla-javascript-without-frameworks/): understand the platform, write only the code you need, and measure the cost. From here you can add pointer interaction (a repulsion force near the cursor), color variation by depth, or a WebGL renderer for thousands of particles — the physics stays exactly the same. Want a hero section with this kind of polish that still loads fast and passes accessibility checks? Our [Landing Page Development](/service/landing-page-development/) service combines considered motion design with performance budgets, and for richer interactive experiences see [Custom Web Application Development](/service/custom-web-application-development/). [Get in touch](/contact-us/) and tell us what you have in mind. ## FAQ **Q:** Why use delta time instead of moving particles a fixed amount per frame? **A:** Displays refresh at different rates, commonly 60, 90, 120 or 144 Hz, and frames are sometimes dropped. If you move particles a fixed distance per frame, the animation runs twice as fast on a 120 Hz screen. Multiplying velocities and forces by the elapsed time in seconds keeps the motion identical on every device. **Q:** How many particles can a Canvas 2D animation handle? **A:** It depends on particle size, drawing method and device, but a subtle background effect rarely needs more than a few hundred particles. Scale the count to the canvas area, cap it, and test on a low-end phone; if you need tens of thousands of particles, WebGL is the better tool. **Q:** Does a decorative canvas animation hurt Core Web Vitals? **A:** A canvas element is not normally reported as the Largest Contentful Paint element, and it does not cause layout shift if it is absolutely positioned. The main risk is main-thread time, which can delay interactions and hurt INP, so keep per-frame work small and pause the animation when it is off-screen. **Q:** Is honoring prefers-reduced-motion enough for accessibility? **A:** It is an essential first step, but WCAG 2.2.2 Pause, Stop, Hide also asks for a way to pause automatically moving content that lasts more than five seconds alongside other content. For subtle decorative effects, providing a visible pause control as well is the safest approach. --- # Data Visualization on the Web: SVG vs Canvas vs WebGL URL: https://hiddlins.com/blog/web-data-visualization-svg-canvas-webgl/ Published: 2026-08-03 · Updated: 2026-08-03 Every chart on the web is eventually drawn by one of three technologies: SVG, the Canvas 2D API or WebGL (with WebGPU now arriving as its successor). They can produce visually identical results, yet they behave completely differently once you add thousands of data points, hover tooltips, animation, screen readers or a phone with a modest GPU. Choosing the wrong one is rarely fatal on day one, but it often becomes painful when the dataset grows or the product team asks for "just one more interaction". This guide explains how each renderer works, where it shines, where it breaks down and how we decide between them on real projects. ## Two mental models: retained and immediate mode The most important difference is not speed but the programming model. **SVG is retained mode.** You describe a scene as a tree of elements — <rect>, <circle>, <path>, <text> — and the browser remembers it. Change an attribute and the browser works out what to repaint. Each mark is a real DOM node with its own events, styles and accessibility information. **Canvas and WebGL are immediate mode.** You issue drawing commands and the browser turns them into pixels in a bitmap. Once drawn, there are no "objects" left — only colored pixels. To change anything, you clear and redraw. To know what the user is pointing at, you have to work it out yourself from your own data. WebGL takes the immediate model further by moving the work to the GPU: you upload data into buffers once and run small programs called shaders that position and color every vertex and pixel in parallel. That is why it handles orders of magnitude more marks, and also why it demands considerably more code and expertise. ## SVG: when the DOM is your friend For the majority of business charts — bar charts, line charts with a few series, donut charts, small multiples, annotated explanatory graphics — SVG is the right default. ### Strengths - **Resolution independence.** Vectors stay crisp at any zoom level and on any pixel density, with no extra work. - **Styling with CSS.** Colors, hover states, transitions, dark mode and print styles can all live in your stylesheet. - **Native interaction.** Every mark can receive pointer and focus events, so tooltips and highlighting are straightforward. - **Accessibility and text.** SVG text is selectable, searchable and can be exposed to assistive technology through roles, titles and descriptions. - **Debuggability.** You can inspect any bar in devtools and see exactly what was rendered. ### An accessible SVG chart Here is a deliberately small, hand-written bar chart. Note the role="img" with a title and description that state the insight, not just the chart type: ``` <figure> <svg viewBox="0 0 320 170" role="img" aria-labelledby="orders-title orders-desc"> <title id="orders-title">Monthly orders, January to March Orders rose from 120 in January to 180 in March.
Orders per month, Q1. Full data in the table below.
``` ### Where SVG struggles Because every mark is a DOM node, cost grows with the number of marks: memory, style recalculation, layout and painting. A few hundred or a couple of thousand elements are typically no problem. Tens of thousands of animated circles will make most devices stutter, and hover handlers on each of them compound the problem. There is no fixed threshold — it depends on the device, the complexity of each shape and how often you update — so treat any number you read, including ours, as a rule of thumb and test on your slowest target device. A common trick is to keep SVG but reduce the node count: draw a 10,000-point line as a single rather than 10,000 circles, and only render individual dots for the hovered point. ## Canvas 2D: pixels on demand The [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API) gives you a bitmap and a set of drawing commands. Its cost depends on how many pixels and draw calls you produce, not on how many objects the browser must track. That makes it a strong choice for dense scatter plots, heatmaps, long time series, real-time streams and any chart that redraws many times per second. ### Handle pixel density yourself A canvas has two sizes: its CSS display size and its internal bitmap size. On a high-density screen, a canvas whose bitmap matches its CSS size looks blurry. Scale the backing store by devicePixelRatio and then scale the context so you can keep drawing in CSS pixels: ``` function setupCanvas(canvas) { const dpr = window.devicePixelRatio || 1; const { width, height } = canvas.getBoundingClientRect(); canvas.width = Math.round(width * dpr); canvas.height = Math.round(height * dpr); const ctx = canvas.getContext('2d'); ctx.setTransform(dpr, 0, 0, dpr, 0, 0); return { ctx, width, height }; } function drawPoints(ctx, points, xScale, yScale) { ctx.fillStyle = '#2563eb'; ctx.beginPath(); // one path, one fill: far fewer draw calls for (const p of points) { const x = xScale(p.x); const y = yScale(p.y); ctx.moveTo(x + 2, y); ctx.arc(x, y, 2, 0, Math.PI * 2); } ctx.fill(); } ``` Batching all points of the same style into one path, as above, is one of the biggest Canvas performance wins. Changing fillStyle, line width or shadows between every mark forces far more state changes. ### Hit testing Without DOM nodes, hover and click require you to map a pointer position back to data. Options, from simplest to most scalable: - **Arithmetic** for regular layouts: a bar chart can compute the hovered bar index from the x coordinate. - **Path2D with isPointInPath()** for a modest number of irregular shapes, such as map regions. - **A spatial index** such as a quadtree or grid for large point sets, so the nearest point is found without scanning everything. ``` import { quadtree } from 'd3-quadtree'; const tree = quadtree() .x(d => xScale(d.x)) .y(d => yScale(d.y)) .addAll(points); canvas.addEventListener('pointermove', (event) => { const rect = canvas.getBoundingClientRect(); const hit = tree.find(event.clientX - rect.left, event.clientY - rect.top, 8); showTooltip(hit); // hit is undefined when nothing is within 8px }); ``` ### Layering Stack several canvases (or a canvas under an SVG) so that static content — axes, gridlines, thousands of data points — is drawn once, while a thin top layer handles frequently changing elements such as the crosshair, selection or tooltip. Redrawing a nearly empty overlay is almost free. ## WebGL and WebGPU: the GPU route [WebGL](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API) exposes the GPU through an OpenGL ES–style API. Instead of looping over points in JavaScript every frame, you upload coordinates to a buffer once and let a vertex shader transform them in parallel: ``` attribute vec2 a_position; // data coordinates uniform vec2 u_scale; // data-to-clip-space scale uniform vec2 u_offset; // pan offset uniform float u_pointSize; void main() { gl_Position = vec4(a_position * u_scale + u_offset, 0.0, 1.0); gl_PointSize = u_pointSize; } ``` Panning and zooming then only means updating two uniforms, even for a million points. That is the kind of workload — dense scatter plots, large time series, flow fields, geospatial layers, network graphs, 3D — where WebGL is the right tool. ### The costs - **Complexity.** Shaders, buffers, blending and precision issues require specialist knowledge. Most teams should use a library rather than raw WebGL. - **Text.** WebGL has no text rendering. Labels are usually drawn with signed-distance-field fonts or, more pragmatically, as HTML or SVG overlays. - **Context limits and loss.** Browsers cap the number of simultaneously active WebGL contexts, so a dashboard with twenty WebGL widgets can lose some. Contexts can also be lost when the GPU resets, and you must handle the webglcontextlost and webglcontextrestored events. - **Battery and heat.** Continuous GPU rendering drains mobile batteries. Render on demand, not in an endless loop. ### Where WebGPU fits The [WebGPU API](https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API) is the modern successor, with a cleaner design and compute shaders that can aggregate, filter or lay out data directly on the GPU. It has shipped in Chromium-based browsers and more recently in other engines on some platforms, but MDN still marks it as not Baseline. Treat it as a progressive enhancement: feature-detect navigator.gpu and fall back to WebGL, which many rendering libraries now do for you. ## Side-by-side comparison The figures below are rough orders of magnitude for smooth interaction on mid-range hardware, not benchmarks; your mileage will vary with shape complexity, update frequency and device. | | | SVG | Canvas 2D | WebGL / WebGPU | Model | Retained (DOM nodes) | Immediate (bitmap) | Immediate (GPU buffers and shaders) | Comfortable mark count | Hundreds to low thousands | Thousands to hundreds of thousands | Hundreds of thousands to millions | Interaction and hit testing | Built in, per element | Manual (math, Path2D, spatial index) | Manual (spatial index, GPU picking) | Styling | CSS | JavaScript drawing state | Shaders | Text and labels | Excellent | Good, not selectable | None natively; use overlays | Accessibility | Can be exposed directly | Requires fallback content and alternatives | Requires fallback content and alternatives | Sharpness when zoomed | Always crisp | Must redraw at new scale | Must redraw at new scale | Development effort | Low | Medium | High | Typical uses | Business charts, explanatory graphics, maps with few regions | Dense plots, heatmaps, real-time streams, animation | Big data scatter, geospatial, 3D, particle-heavy visuals ## Performance techniques that apply to all three The fastest mark is the one you never draw. Before switching renderers, reduce the work. ### Reduce the data A line chart 800 pixels wide cannot show more than a few thousand meaningful points. Downsample long series with an algorithm that preserves visual shape, such as min/max per pixel column or Largest-Triangle-Three-Buckets, and fetch more detail only when the user zooms in. Aggregate dense scatter plots into hexbins or density grids. Often this lets you stay with SVG and keep all its advantages. ### Move work off the main thread Parsing large JSON, computing aggregates and laying out graphs can block input and hurt Interaction to Next Paint. Do that work in a Web Worker. With [OffscreenCanvas](https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas), you can even render a Canvas or WebGL chart entirely inside a worker: ``` // main.js const offscreen = canvas.transferControlToOffscreen(); const worker = new Worker('chart-worker.js'); worker.postMessage({ canvas: offscreen, dpr: devicePixelRatio }, [offscreen]); // chart-worker.js self.onmessage = ({ data }) => { const ctx = data.canvas.getContext('2d'); ctx.scale(data.dpr, data.dpr); // ...fetch, aggregate and draw without touching the main thread }; ``` ### Render on demand Redraw only when data, size or interaction state changes, and coalesce multiple changes into a single requestAnimationFrame callback. A chart that idles at zero CPU is better for battery life and for every other script on the page. If you want to see this pattern applied to continuous animation, our [Canvas particle animation tutorial](/blog/canvas-particle-animation-tutorial/) walks through a frame loop, delta time and device pixel ratio handling in detail. ### Mind page weight A charting library can easily outweigh the rest of your page. Import only the modules you use, lazy-load charts below the fold and consider whether a static SVG generated on the server would answer the question just as well. Our article on [modern JavaScript without the bloat](/blog/vanilla-javascript-without-frameworks/) covers these trade-offs more broadly. ## Accessible charts, whatever the renderer A chart is a way of communicating data, and some of your readers will not see it. Regardless of the technology: - **State the insight in text.** A title such as "Orders grew 50% in Q1" plus a short description serves everyone, including people skimming. - **Provide the data.** An HTML table, which can be visually collapsed behind a "Show data" toggle, or a CSV download lets screen reader users and analysts explore the numbers. - **Do not rely on color alone.** Use direct labels, patterns or shapes so series remain distinguishable for people with color vision deficiencies, and keep graphical elements at a 3:1 contrast ratio against adjacent colors as WCAG's non-text contrast criterion requires. - **Make interactions keyboard-operable.** If tooltips reveal values on hover, offer a way to reach the same information by keyboard. - **Use canvas fallback content.** Content placed between and is exposed to assistive technology and is a good place for a summary or link to the data table. - **Respect reduced motion.** Skip entrance animations and animated transitions when prefers-reduced-motion: reduce is set. Our [WCAG 2.2 guide](/blog/wcag-accessibility-guide-small-business/) explains the relevant success criteria in plain language. ## Choosing a renderer and a library In practice you will rarely choose a renderer in isolation; you will choose a library that uses one or more of them. Low-level toolkits such as D3 let you target SVG or Canvas yourself. Higher-level libraries tend to have a default — for example Chart.js draws to Canvas, Observable Plot outputs SVG, and Apache ECharts can switch between Canvas and SVG renderers — while GPU-focused libraries such as deck.gl target WebGL and are adding WebGPU. Hybrid setups are common and sensible: a WebGL layer for millions of points, with SVG axes and HTML tooltips on top. **Key takeaways** - Default to SVG for typical business charts: it is accessible, stylable and easy to debug. - Move to Canvas when mark counts reach many thousands or you redraw continuously, and plan for hit testing and pixel density. - Use WebGL for very large or GPU-friendly workloads, ideally through a library; treat WebGPU as an enhancement for now. - Reduce and aggregate data before reaching for a heavier renderer. - Every chart needs a text alternative and access to the underlying data. ## From data to decisions The best visualization is not the one with the most impressive rendering engine; it is the one that makes the right insight obvious to every reader, loads quickly and stays responsive on the devices your audience actually uses. Start with the question the chart should answer, estimate how much data it really needs, and only then pick the renderer that fits. If you are exploring models in the browser too, our article on [practical machine learning with JavaScript](/blog/machine-learning-in-the-browser/) pairs naturally with interactive charts. Building a dashboard, an internal analytics tool or a data-heavy product? Our [Custom Web Application Development](/service/custom-web-application-development/) service covers everything from data pipelines to fast, accessible interactive charts. [Tell us about your data](/contact-us/) and what decisions it needs to support, and we will recommend an approach that fits. ## FAQ **Q:** Is SVG or Canvas better for charts? **A:** SVG is usually better for charts with a modest number of marks because every shape is a DOM element that can be styled, made interactive and exposed to assistive technology. Canvas is better when you draw thousands to hundreds of thousands of marks or redraw constantly, at the cost of handling hit testing and accessibility yourself. **Q:** When do I actually need WebGL for a chart? **A:** Reach for WebGL when you need to render or animate very large numbers of points, lines or tiles smoothly, such as dense scatter plots, large time series, geospatial layers or 3D scenes. For typical business dashboards, SVG or Canvas is simpler and perfectly fast. **Q:** Should I use WebGPU instead of WebGL? **A:** WebGPU offers a more modern API and compute shaders, but MDN still lists it as not yet Baseline because support is not universal across widely used browsers. For production charts today, use WebGL or a library that can fall back to it, and treat WebGPU as a progressive enhancement. **Q:** How do I make a Canvas or WebGL chart accessible? **A:** Give the chart a text alternative that states the key insight, provide the underlying data as an HTML table or downloadable file, and make interactive features available by keyboard. Fallback content placed inside the canvas element is exposed to assistive technology, and an adjacent summary helps every reader. --- # UI/UX Principles That Actually Move Conversion Rates URL: https://hiddlins.com/blog/ux-principles-conversion/ Published: 2026-07-24 · Updated: 2026-07-24 Most conversion problems are not solved by a cleverer headline or a new shade of button. They are solved by removing the small moments of confusion, doubt and effort that make people hesitate and leave. That is what good UX does. In this guide we focus on the principles that consistently make a measurable difference on real websites — landing pages, lead forms, sign-ups and checkouts — and on how to verify the effect instead of trusting a gut feeling or a "best practice" from someone else's audience. ## What a conversion actually measures A conversion is simply a visitor completing an action you care about. The trap is optimizing a number without being clear about what it represents. Before touching any design, write down your conversion goals and how they connect. ### Macro and micro conversions A **macro conversion** is the primary outcome: a purchase, a booked call, a submitted quote request. **Micro conversions** are the steps that lead there: viewing pricing, adding to cart, starting a form, opening a product detail. Tracking micro conversions shows where people drop off, which tells you where design effort will pay off. A page with plenty of "add to cart" clicks but few completed orders has a checkout problem, not a product page problem. ### Quality over volume It is easy to raise a conversion rate by lowering the bar — a "free guide" pop-up on every page will collect email addresses, but if none of them ever buys, nothing improved. Track what happens after the conversion as well: lead quality, refund rates, repeat purchases. Good UX increases conversions from people who genuinely want what you offer; manipulative UX increases noise. ## Clarity beats cleverness Visitors decide very quickly whether a page is relevant to them. If they cannot answer three questions almost immediately — what is this, is it for me, and what do I do next — many will leave without scrolling. ### Lead with the value, not the brand slogan A headline like "Elevate your potential" says nothing. "Accounting software for freelancers that files your quarterly taxes" says almost everything. Write the headline in the visitor's language, follow it with a subheading that adds the key differentiator or proof, and place one obvious primary action nearby. Clever wordplay can work in a subheading once the meaning is already clear. ### Visual hierarchy does the explaining People scan before they read. Size, weight, contrast, whitespace and position tell them what matters most. Every screen should have one dominant element and one primary action; if everything is bold, nothing is. A quick test: blur a screenshot of your page or squint at it. The things you can still identify are what visitors notice first. If that is a decorative image or a cookie banner rather than your offer and call to action, the hierarchy needs work. ### Familiar beats novel Jakob's Law, popularized by Nielsen Norman Group, observes that users spend most of their time on other sites, so they expect yours to work the same way. Logo top-left linking home, navigation across the top or behind a recognizable menu icon, the cart top-right, underlined or clearly styled links. Novel navigation patterns make people learn your interface before they can learn about your product. The well-known [10 usability heuristics](https://www.nngroup.com/articles/ten-usability-heuristics/) are still one of the best checklists for spotting these issues. ## Reduce choices and cognitive load Every decision you ask a visitor to make costs a little attention. Hick's Law describes how decision time grows with the number and complexity of choices; in practice, the bigger risk is not slowness but abandonment — people postpone decisions that feel hard. - **Limit primary options.** Three clearly differentiated pricing tiers are easier to choose between than six. Highlight the one that suits most customers. - **Use smart defaults.** Pre-select the most common shipping method, the country detected from the address and the plan most people pick. Defaults should serve the user, not quietly upsell them. - **Disclose progressively.** Show advanced options only when someone asks for them. A "Have a coupon code?" link instead of an always-visible field avoids sending shoppers off to hunt for discounts mid-checkout. - **Chunk long processes.** A long form split into short, clearly labeled steps with visible progress feels lighter, as long as each step is meaningful and back navigation preserves what was entered. - **Remove competing calls to action.** A landing page for one offer should not also push the newsletter, the blog and three social networks at the same level. Semantic, well-structured markup helps here too: clear headings and lists make pages easier to scan for everyone, including assistive technology users. We cover that foundation in [our semantic HTML article](/blog/semantic-html-seo-accessibility/). ## Make the next action easy to hit Fitts's Law tells us that the time to reach a target depends on its distance and size: big, close targets are fast; small, distant ones are slow and error-prone. On touch screens, that translates into concrete rules. ### Size and spacing WCAG 2.2 introduced success criterion 2.5.8, Target Size (Minimum), which requires interactive targets to be at least 24 by 24 CSS pixels at level AA, with exceptions such as inline links and sufficiently spaced targets (see the [W3C Understanding document](https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html)). That is a floor, not a goal. For primary buttons on mobile, a height of roughly 44–48 CSS pixels with comfortable spacing is far more forgiving. Our [WCAG 2.2 guide for small businesses](/blog/wcag-accessibility-guide-small-business/) covers this and the other new criteria in detail. ### Placement Put the primary action where the eye and thumb already are. On long mobile product pages, a sticky "Add to cart" bar keeps the action within reach without forcing people to scroll back up. Make sure sticky elements do not cover focused fields or important content, which is both an annoyance and an accessibility failure. ### Button copy that describes the outcome "Submit" describes what the browser does. "Get my free quote", "Start 14-day trial" or "Pay $48.00" describe what the visitor gets. Specific labels reduce uncertainty about what happens after the click, and stating the amount on a payment button removes one last moment of doubt. ## Forms: where conversions are won or lost Forms are the point where interest turns into commitment, and they are where most friction hides. The principles are well established, and the [web.dev guide to payment and address forms](https://web.dev/articles/payment-and-address-form-best-practices) is an excellent reference. ### Ask for less Every field should earn its place. Do you need a phone number to send a quote? A company name for a newsletter? Separate first and last name fields, or would one "Full name" field do? Optional fields still cost attention, so remove them rather than marking them optional when you can. ### Help the browser help the user Correct type, inputmode and autocomplete attributes let browsers show the right keyboard and fill in saved details with one tap. This is one of the cheapest conversion improvements available: ``` ``` | | Field | Attributes to use | Common mistake | Email | type="email" autocomplete="email" | Asking people to type it twice | Full name | autocomplete="name" | Splitting into fields that do not fit every naming convention | Phone | type="tel" autocomplete="tel" | Rejecting spaces, brackets or a leading + | Street address | autocomplete="address-line1" / "address-line2" | Forcing a postcode lookup with no manual fallback | Postcode | autocomplete="postal-code" | Using type="number", which strips leading zeros | One-time code | autocomplete="one-time-code" inputmode="numeric" | Splitting the code into six separate boxes that break paste ### Labels, validation and errors Use visible labels above fields; placeholder text disappears as soon as someone starts typing and usually has poor contrast. Validate when a field loses focus or on submit, not on every keystroke — nobody wants to be told their email is invalid after typing the first letter. When something is wrong, say what and how to fix it ("Enter a 5-digit ZIP code, like 90210"), place the message next to the field, keep everything the user has already entered and move focus to the first error on submit. ### Do not force account creation Requiring an account before purchase is one of the most consistently reported reasons for checkout abandonment. Offer guest checkout and invite people to save their details after the order is placed, when the benefit is obvious and the risk is gone. If you sell with WooCommerce, pair a short checkout with a fast one; our guide to [WooCommerce performance](/blog/woocommerce-performance-optimization/) explains how to keep cart and checkout responsive as the store grows. ## Build trust honestly People convert when perceived value outweighs perceived risk. You lower the risk side with credible signals, and you destroy it with anything that feels like a trick. - **Show real proof.** Genuine reviews with names (where customers agree), concrete examples of your work and recognizable integrations or certifications that you actually hold. Never invent testimonials, numbers or logos — beyond being dishonest, fake reviews are illegal in many jurisdictions. - **Be transparent about price.** Show shipping costs, taxes and recurring fees early. Unexpected costs at the final step are a classic abandonment trigger, and "drip pricing" is increasingly targeted by regulators. - **Make contact easy.** A real address, a visible contact route and clear returns or refund terms signal that there is an accountable business behind the site. - **Explain the next step.** "We will reply within one working day with a fixed quote" turns an anonymous form into a predictable process. - **Avoid dark patterns.** Pre-ticked add-ons, confirm-shaming ("No thanks, I don't like saving money"), fake countdown timers and hard-to-find cancellation links may lift a metric briefly, but they damage trust and repeat business. **A quick credibility audit** - Can a first-time visitor find your prices, contact details and refund policy within two clicks? - Is every claim on the page something you could prove if asked? - Does the page still look trustworthy on a cheap Android phone in bright sunlight? ## Speed and feedback are part of the design Performance is not just an engineering metric; it is how the interface feels. A page that renders slowly loses people before they read the headline, and a button that does not visibly react makes people click again, double-submit or give up. ### Respond within a beat Google's Interaction to Next Paint metric considers 200 milliseconds or less "good" for the time between an interaction and the next visual update. Even if the real work takes longer — a payment authorization, a search — show something immediately: a pressed state, a spinner inside the button, a disabled state that prevents double submission, or optimistic UI that updates instantly and reconciles later. Our [Core Web Vitals guide](/blog/core-web-vitals-guide/) explains how to measure and fix slow interactions. ### Avoid layout shift Few things cause misclicks like a button that moves just as someone taps it because an image or banner loaded above it. Reserve space for images, ads and embeds, and never inject content above what the user is currently reading or interacting with. ### Confirm success clearly After a conversion, the confirmation page is part of the experience. Confirm what happened, what happens next and when, and offer a sensible next step. A vague "Thank you" leaves people wondering whether their order or enquiry actually went through. ## Test changes properly Principles give you good hypotheses, not guaranteed results. Your audience, offer and context may behave differently, so verify. ### Start with qualitative research Watching five people try to complete a task on your site will reveal the most serious usability problems faster than months of analytics. Ask them to think aloud and resist the urge to help. Session recordings and on-page surveys ("What stopped you from signing up today?") complement this at scale; make sure any recording tool masks personal data and respects consent. ### A/B testing without fooling yourself - **Estimate sample size first.** Low-traffic sites often cannot detect realistic improvements in a reasonable time frame. If a test would need six months, ship the change based on research and monitor it instead. - **Do not stop when it "looks significant".** Repeatedly checking results and stopping at the first good-looking moment dramatically increases false positives. Decide duration in advance and run in full weeks to cover weekday and weekend behavior. - **Test meaningful changes.** Button color tests rarely matter; tests of the offer, the message, the form length or the checkout flow often do. - **Watch guardrail metrics.** A variant that increases sign-ups but also increases refunds or support tickets is not a winner. - **Mind performance.** Client-side testing tools that hide the page until the variant loads can hurt LCP, which affects every variant equally and muddies results. **Key takeaways** - Define macro and micro conversions so you know where people drop off. - Clear value, clear hierarchy and one primary action beat clever copy. - Reduce choices, use honest defaults and disclose complexity progressively. - Shorter forms with correct autocomplete attributes are one of the cheapest wins available. - Trust is earned with transparency and real proof, and lost with dark patterns. - Validate with users and well-run tests rather than borrowed best practices. ## Turning principles into results None of these principles is new, and that is the point: they keep working because they are rooted in how people perceive, decide and act. The difficulty is applying them consistently across every page, form and state of your site — including the error messages and edge cases nobody designs on purpose. If you are planning a new page or want to know why an existing one underperforms, our [Landing Page Development](/service/landing-page-development/) service builds focused, fast pages around a single conversion goal, and for larger sites our [WordPress Website Development](/service/wordpress-website-development/) projects bake these principles into the design system from the start. [Contact us](/contact-us/) with a link to the page you want to improve and we will share our first observations. ## FAQ **Q:** What is the fastest UX change that usually improves conversions? **A:** Clarifying the primary message and call to action above the fold is often the quickest win, followed closely by removing unnecessary form fields. Neither requires a redesign, and both reduce the effort a visitor needs to decide and act. **Q:** Do I need A/B testing to improve conversion rates? **A:** Not always. Low-traffic sites rarely reach statistically reliable A/B results, so they get more value from usability testing, session reviews and fixing obvious friction. A/B testing becomes worthwhile once you have enough conversions per variant to detect realistic differences. **Q:** Are urgency timers and scarcity messages good UX? **A:** Only when they are true. Genuine stock levels or real deadlines help people decide, but fake countdowns and invented scarcity are dark patterns that erode trust and may breach consumer protection rules in many countries. **Q:** How big should buttons and tap targets be? **A:** WCAG 2.2 sets a minimum of 24 by 24 CSS pixels for targets at level AA, with some exceptions. For primary actions on touch screens, aim considerably larger, around 44 to 48 CSS pixels in height, and leave enough spacing so people do not hit the wrong control. --- # WooCommerce Performance: How to Keep an Online Store Fast as It Grows URL: https://hiddlins.com/blog/woocommerce-performance-optimization/ Published: 2026-07-14 · Updated: 2026-07-14 A brand-new WooCommerce store with twenty products and a clean theme is usually quick. Two years later, with thousands of products, tens of thousands of orders, a dozen extensions and a marketing stack bolted onto every page, the same store can feel like it is wading through mud — especially at checkout, which is exactly where speed matters most. The good news is that WooCommerce scales well when each layer of the stack is doing its job. This guide walks through those layers in the order we tackle them on real stores: measurement, caching, the database, background jobs, front-end weight, catalog search and, finally, the checkout itself. ## Why WooCommerce stores slow down as they grow Most performance problems in WooCommerce are not caused by WooCommerce itself, but by how stores accumulate data and code over time. Understanding the three main forces makes the fixes much easier to prioritize. ### Personalized pages cannot be cached like a blog A content site can serve almost every request from a page cache. A store cannot: the cart, checkout and account pages are unique to each shopper, and once a visitor adds something to their cart, WooCommerce sets session cookies that should send them past the page cache for the rest of their visit. That means a growing share of your traffic hits PHP and MySQL directly — and that share is made up of your most valuable visitors, the ones about to buy. ### Data grows quietly Orders, order notes, customer sessions, scheduled actions, logs, transients and plugin settings all live in the database. None of them is a problem on day one. After a few years, tables that nobody looks at can hold millions of rows, and queries that were instant become slow, particularly in the admin and in reports. ### Plugins accrete Each extension usually adds its own scripts, styles, database queries and sometimes remote API calls. Individually they look harmless; together they can double page weight and add hundreds of milliseconds of server time to every uncached request. Many load their assets on every page even if they only matter on one. ## Measure before you optimize Guessing is the most expensive way to speed up a store. Before changing anything, establish a baseline you can compare against, and measure both the anonymous storefront and the logged-in, cart-carrying experience, because they behave very differently. ### Field data first Start with real-user data. Google's Core Web Vitals thresholds — Largest Contentful Paint at or under 2.5 seconds, Interaction to Next Paint at or under 200 milliseconds and Cumulative Layout Shift at or under 0.1, measured at the 75th percentile — are documented on [web.dev](https://web.dev/articles/vitals). Search Console's Core Web Vitals report and PageSpeed Insights show this field data when your store has enough traffic. Look at product pages and category pages separately; they usually have different bottlenecks. Our [Core Web Vitals guide](/blog/core-web-vitals-guide/) explains how to read these reports and what each metric is really telling you. ### Server-side profiling Field data tells you that something is slow; server profiling tells you why. On a staging copy, a plugin such as Query Monitor shows slow and duplicate queries, hooks and HTTP API calls per request. Your host's PHP slow log and MySQL slow query log, or an APM tool if you have one, reveal patterns across real traffic. | | What to measure | Where | What "bad" usually points to | TTFB for anonymous visitors | PageSpeed Insights, WebPageTest, curl | Page cache missing, misconfigured or frequently purged | TTFB with items in the cart | Browser devtools on staging | Slow PHP, heavy plugins, no object cache | Queries per request | Query Monitor | Plugins querying in loops, missing lookup tables | LCP on product pages | Search Console, PageSpeed Insights | Oversized gallery images, lazy-loaded hero image, render-blocking CSS | INP on product and checkout pages | Search Console, browser Performance panel | Heavy JavaScript, third-party scripts, variation logic | Admin page load times | Query Monitor in wp-admin | Autoloaded options, scheduled action backlog, postmeta-based orders ## Get the caching layers and hosting right Caching is not one thing. A healthy store uses several layers, each solving a different problem. Missing any one of them pushes load onto the layers beneath it. ### Full-page cache with correct bypass rules Serve anonymous catalog traffic — home, category, tag and product pages — from a page cache at the server or CDN edge. The critical part is the bypass rules: never cache /cart/, /checkout/ or /my-account/, never cache requests that add to the cart, and skip the cache for any request carrying WooCommerce session, cart or login cookies. A simplified Nginx FastCGI cache configuration looks like this: ``` set $skip_cache 0; # Never cache POST requests or URLs with query strings like ?add-to-cart= if ($request_method = POST) { set $skip_cache 1; } if ($query_string != "") { set $skip_cache 1; } # Personalized WooCommerce pages if ($request_uri ~* "/(cart|checkout|my-account)/") { set $skip_cache 1; } # Shoppers with a cart or session, and logged-in users if ($http_cookie ~* "woocommerce_items_in_cart|wp_woocommerce_session_|wordpress_logged_in_") { set $skip_cache 1; } fastcgi_cache_bypass $skip_cache; fastcgi_no_cache $skip_cache; ``` Managed WordPress hosts and caching plugins usually ship WooCommerce-aware rules, but verify them rather than assuming: add a product to the cart in a private window and confirm the response headers show a cache bypass on subsequent pages. ### Persistent object cache For every request that skips the page cache, a persistent object cache such as Redis or Memcached stores the results of repeated database lookups — options, product objects, term data — in memory between requests. On stores with many logged-in customers or heavy admin usage, this is often the single biggest server-side win. WordPress Site Health will even flag the absence of a persistent object cache on sites it judges large enough to benefit. ### PHP version, OPcache and workers Run a currently supported PHP 8 release with OPcache enabled; each modern version has brought performance and language improvements, which we cover in [our PHP 8 article](/blog/modern-php-8-features/). Also check how many PHP workers your plan provides. Because carts and checkouts bypass the cache, a sale or email campaign can exhaust a small worker pool quickly, and requests then queue rather than fail — which shows up as mysterious slowness during your busiest hours. ### CDN and browser caching Static assets — images, CSS, JavaScript and fonts — should be served from a CDN with long cache lifetimes and fingerprinted filenames, so repeat visitors and later page views download almost nothing. ## Keep the database lean A tidy database keeps uncached requests and the admin fast. These are the areas we check on every store. ### Migrate orders to HPOS Historically, WooCommerce stored orders as posts with dozens of postmeta rows each, sharing tables with every page, product and revision on the site. High-Performance Order Storage moves orders into dedicated tables such as wc_orders, wc_order_addresses and wc_orders_meta, designed and indexed for order queries. According to the [WooCommerce developer documentation](https://developer.woocommerce.com/docs/features/orders/high-performance-order-storage/), HPOS has been enabled by default for new installations since WooCommerce 8.2 (October 2023). Older stores can migrate from WooCommerce → Settings → Advanced → Features: enable compatibility mode so both storage systems stay in sync, confirm that your extensions declare compatibility, then switch the authoritative store to HPOS. ### Audit autoloaded options Options marked for autoloading are loaded on every single request. Plugins sometimes store large blobs here — logs, caches, settings for features you no longer use — and the cost is paid everywhere. Since WordPress 6.6, Site Health warns when autoloaded data becomes large, and autoload values can be on, off, auto, auto-on or auto-off as well as the legacy yes/no. This query lists the biggest offenders: ``` SELECT option_name, LENGTH(option_value) AS bytes FROM wp_options WHERE autoload IN ('yes', 'on', 'auto-on', 'auto') ORDER BY bytes DESC LIMIT 20; ``` Options belonging to plugins you have removed can usually be deleted; options for active plugins should be investigated before you change them, ideally on staging. ### Expired transients, sessions and logs Transients are meant to be temporary cached values (see the [Transients API documentation](https://developer.wordpress.org/apis/transients/)), but without a persistent object cache they live in wp_options and expired ones are only cleaned up periodically. WooCommerce's own session table and log storage also grow with traffic. Make sure scheduled cleanup actually runs — which leads directly to background jobs. ### Lookup tables WooCommerce maintains lookup tables, such as the product meta lookup table for price, stock and rating sorting and the attribute lookup table for layered navigation filters. If they fall out of sync after imports or direct database edits, queries fall back to slower paths or return wrong results. They can be regenerated from WooCommerce → Status → Tools. **Back up before database work** - Take a full database backup and test it restores before deleting options or migrating order storage. - Work on a staging copy first, especially for HPOS migration on stores with many orders. - Never "optimize" by deleting rows you do not understand; orphaned-looking data is sometimes still used. ## Tame background jobs and scheduled actions WooCommerce relies heavily on background processing: sending emails, syncing stock, processing webhooks, running subscription renewals, importing analytics data and cleaning up sessions. Two systems drive this work, and both deserve attention. ### Replace traffic-triggered WP-Cron with a real cron job By default, WP-Cron checks for due tasks during normal page loads. On a quiet store, tasks run late; on a busy one, the checks add overhead to visitor requests. Disable the built-in trigger and run due events from the server's scheduler instead: ``` // wp-config.php define( 'DISABLE_WP_CRON', true ); ``` ``` # crontab: run due WordPress events every minute via WP-CLI * * * * * cd /var/www/example && wp cron event run --due-now --quiet ``` ### Keep Action Scheduler healthy Action Scheduler is the queue WooCommerce and many extensions use for larger jobs. Check WooCommerce → Status → Scheduled Actions regularly. A growing number of pending or failed actions means something is stuck — often an extension calling an external API that times out. Completed actions are kept for a retention period (30 days by default) before being purged; on high-volume stores you can shorten it: ``` add_filter( 'action_scheduler_retention_period', function () { return 7 * DAY_IN_SECONDS; } ); ``` For very large backlogs, WP-CLI's wp action-scheduler run command lets you process the queue outside web requests rather than letting it compete with shoppers. ## Control front-end weight on product and category pages Server speed gets the first byte out quickly, but the browser still has to download, parse and execute everything you send. On most stores we audit, front-end weight is where the largest Core Web Vitals gains are. ### Images: right size, right format, right priority Product photography is usually the LCP element. Upload images at a sensible maximum size, let WordPress generate responsive srcset sizes, and serve modern formats such as WebP or AVIF (WordPress supports AVIF uploads since 6.5 when the server's image library does). Never lazy-load the main product image or the first row of a category grid; WordPress adds fetchpriority="high" to the image it judges most likely to be the LCP element, but custom galleries and sliders often break that heuristic, so check the rendered HTML. ### Load scripts only where they are used Slider libraries, form plugins, review widgets and chat tools commonly enqueue assets on every page. Dequeue them where they are not needed: ``` add_action( 'wp_enqueue_scripts', function () { // The contact form only lives on the contact page. if ( ! is_page( 'contact-us' ) ) { wp_dequeue_script( 'contact-form-7' ); wp_dequeue_style( 'contact-form-7' ); } }, 100 ); ``` Script handles vary by plugin, so confirm them with Query Monitor's "Scripts" panel before dequeuing. If you find yourself fighting a theme that ships megabytes of JavaScript, our article on [modern JavaScript without the bloat](/blog/vanilla-javascript-without-frameworks/) explains how much interactivity you can achieve with very little code. ### Cart fragments and mini-carts The legacy cart fragments script makes an AJAX request to refresh the mini-cart, and on uncached setups this request hits PHP on every page view. Recent WooCommerce versions no longer load it everywhere by default, but many themes and plugins re-enqueue it. If your header cart works without it — for example because you use the Mini-Cart block — remove it and test thoroughly. ### Variable products When a product has more variations than the woocommerce_ajax_variation_threshold (30 by default), WooCommerce loads variation data on demand via AJAX instead of embedding it all in the page. Raising the threshold makes the swatches feel instant but bloats the HTML; lowering it does the opposite. For products with hundreds of variations, consider whether some attributes should really be separate products. ## Catalog, filtering and search at scale Default WordPress search uses LIKE queries against post content. That is fine for a few hundred products, but relevance is poor and performance degrades with large catalogs. Stores with thousands of SKUs benefit from a dedicated search index — a hosted search service or a self-managed engine such as Elasticsearch or OpenSearch — which returns results in milliseconds and handles typos, synonyms and faceting. Faceted filters deserve the same scrutiny. Filters that combine many attributes, price ranges and stock status can generate expensive queries, and every unique combination produces a URL that is unlikely to be cached. Keep filter combinations sensible, make sure the attribute lookup table is in use, and prevent search engines from crawling infinite filter permutations with sensible noindex and canonical rules. Pagination should use a fixed, reasonable number of products per page rather than "show all". ## Keep cart and checkout fast Checkout is uncached by definition, so every millisecond is real server work, and every heavy script directly hurts INP at the moment of purchase. - **Use the block-based Cart and Checkout.** They have been the default for new installations since WooCommerce 8.3 and avoid many of the full-page reloads of the legacy shortcode checkout. Confirm your payment and shipping extensions support them first. - **Load payment scripts only on checkout.** Some gateways inject their SDK site-wide to power express buttons. If you do not show express checkout on product pages, there is no reason to load it there. - **Audit third-party tags.** Analytics, heatmaps, A/B testing and ad pixels compete with your checkout for the main thread. Remove what nobody looks at and defer what remains. - **Watch slow external calls.** Real-time shipping rate APIs, tax services and fraud checks run during checkout. Cache rates where the provider allows it and set sensible timeouts. - **Reduce form friction.** Fewer fields and correct autocomplete attributes make checkout feel faster even when the server is unchanged — see our piece on [UX principles that move conversion rates](/blog/ux-principles-conversion/). Finally, keep the store secure and updated: an outdated plugin is both a security and a performance liability, and our [WordPress security hardening checklist](/blog/wordpress-security-hardening/) covers the update and monitoring routine we recommend. **Key takeaways** - Measure anonymous and cart-carrying visitors separately; they hit completely different code paths. - Page cache the catalog, bypass it for anyone with a cart, and add a persistent object cache for everything else. - Migrate to HPOS, audit autoloaded options and keep Action Scheduler and cron healthy. - Most Core Web Vitals gains come from images and scripts on product and category pages. - Treat checkout as sacred: minimal scripts, fast external calls, short forms. ## Building a store that stays fast WooCommerce performance is not a one-off project; it is a habit. Stores that stay fast review their plugin list every quarter, check Scheduled Actions and autoloaded options during routine maintenance, test checkout after every significant update and keep an eye on field data rather than a single lab score. Each of those checks takes minutes, while recovering from years of neglect can take weeks. If your store has slowed down as it has grown, our [Performance & Technical SEO Audit](/service/performance-seo-audit/) pinpoints exactly where the time goes and gives you a prioritized fix list, and our [WooCommerce Store Development](/service/woocommerce-store-development/) service builds stores with these practices from day one. [Get in touch](/contact-us/) and tell us about your store — we will tell you honestly where we think the biggest wins are. ## FAQ **Q:** Can I use full-page caching on a WooCommerce store? **A:** Yes, for anonymous visitors on catalog pages such as the home page, categories and product pages. Cart, checkout and account pages must never be cached, and any visitor carrying WooCommerce session or cart cookies should bypass the page cache so they always see their own cart. **Q:** What is HPOS and should I enable it? **A:** High-Performance Order Storage moves orders out of the generic posts and postmeta tables into dedicated, indexed order tables. It has been the default for new WooCommerce installations since version 8.2, and older stores should migrate once their extensions are confirmed compatible, using the built-in sync and compatibility mode to switch safely. **Q:** Do I need Redis or Memcached for WooCommerce? **A:** A persistent object cache is not strictly required, but it helps noticeably on stores with many logged-in customers, large catalogs or heavy admin use, because those requests cannot be served from the page cache. WordPress Site Health even recommends one when it detects a site that would benefit. **Q:** Why is my WooCommerce admin slow even though the storefront is fast? **A:** The admin is never page-cached, so it exposes every slow query, oversized autoloaded option and overloaded background queue. Common culprits are a bloated Action Scheduler table, orders still stored in postmeta, analytics imports and plugins that run remote requests on every admin page load. --- # WordPress Security Hardening: A Layered, Practical Checklist URL: https://hiddlins.com/blog/wordpress-security-hardening/ Published: 2026-07-04 · Updated: 2026-07-04 WordPress powers a huge share of the web, which makes it a constant target for automated attacks. The good news is that WordPress core is mature, actively maintained and patched quickly. The overwhelming majority of real-world compromises come through the same few doors: outdated or abandoned plugins, weak or reused passwords, poorly configured hosting and missing backups. Security is not a single plugin you install; it is a set of layers, each of which limits the damage if another fails. This checklist walks through those layers in order of impact, with the configuration snippets we actually use. ## Understand the threat model first Most attacks on WordPress sites are not personal. Bots scan millions of sites for known vulnerable plugin versions, try leaked username and password combinations against wp-login.php and XML-RPC, and look for exposed files such as backups or debug logs. A successful compromise typically ends in SEO spam, redirects to scam pages, malware distribution, card skimming on checkout pages or the server being used to attack others. Industry vulnerability reports from WordPress security vendors consistently show that the vast majority of newly disclosed WordPress vulnerabilities are in plugins, with a smaller share in themes and only a handful in core. The most common classes match the broader [OWASP Top 10](https://owasp.org/www-project-top-ten/): cross-site scripting, broken access control, injection and cross-site request forgery. That tells you where to focus. | | Layer | Main risk addressed | Key controls | Effort | Updates & plugin hygiene | Known vulnerabilities | Timely updates, fewer plugins, no abandoned or nulled code | Low, ongoing | Authentication | Credential stuffing, brute force | Unique passwords, 2FA, least privilege, login rate limiting | Low | Configuration | Escalation after a breach | wp-config hardening, disabled file editing, debug off | Low | Server | Code execution, data exposure | Supported PHP, file permissions, no PHP in uploads, TLS | Medium | Browser | XSS impact, clickjacking | Security headers, Content Security Policy | Medium | Detection & recovery | Undetected compromise, data loss | WAF, monitoring, logging, tested off-site backups | Medium, ongoing ## Layer 1: Updates and plugin hygiene Keeping software current is the highest-impact security task, and the least glamorous. WordPress has applied minor (security and maintenance) core releases automatically since version 3.7, and since version 5.5 you can enable automatic updates for individual plugins and themes from the dashboard. ### Update strategy - **Core minor releases**: leave automatic updates on. They are small and focused on fixes. - **Plugins and themes**: enable auto-updates for simple, well-maintained plugins. For business-critical extensions — payment gateways, membership systems, page builders — test updates on a staging copy first, but do it within days, not months. - **Security releases**: apply immediately. Attackers often begin scanning for a vulnerability within hours of its public disclosure. ### Reduce your attack surface Every plugin is code running with full access to your database. Remove anything deactivated (inactive plugins can still be exploited if their files are reachable), replace plugins that have not been updated in a long time, and prefer one well-maintained plugin over three small ones doing overlapping jobs. Never install "nulled" (pirated) premium themes or plugins: they are a common delivery mechanism for backdoors. Your PHP version is part of this layer too. Branches that are past end-of-life receive no security fixes; our overview of [modern PHP 8](/blog/modern-php-8-features/) includes the current support timeline. ## Layer 2: Authentication and access control Credential attacks are relentless and cheap for attackers. Make them useless. - **Unique, long passwords** for every account, stored in a password manager. Reused passwords from other breaches are the fuel for credential stuffing. - **Two-factor authentication** for every account that can publish or administer — at minimum administrators, editors and shop managers. The Two Factor plugin maintained by WordPress contributors, or the 2FA feature of a reputable security suite, both work; passkeys are increasingly supported too. - **Least privilege.** Most people who write content need the Editor or Author role, not Administrator. Audit users regularly and remove former staff and agencies promptly. - **Rate-limit logins.** Limit failed attempts at the server, CDN or plugin level to blunt brute-force attacks. - **Application passwords**, available since WordPress 5.6, let integrations use the REST API with revocable, per-application credentials instead of a real user password. ### XML-RPC and user enumeration XML-RPC (xmlrpc.php) predates the REST API and supports methods that let attackers try many passwords in a single request. If nothing on your site needs it, block it at the server or with a plugin. Similarly, author archives and the REST users endpoint reveal usernames; that is not a vulnerability in itself, but there is little reason to make usernames easy to collect, and it makes strong passwords and 2FA even more important. ## Layer 3: Hardening wp-config.php A few constants in wp-config.php remove capabilities an attacker would love to have after compromising an admin account. The official [Hardening WordPress](https://developer.wordpress.org/advanced-administration/security/hardening/) handbook covers them in detail. ``` Require all denied ``` On Nginx, inside the server block: ``` # No PHP execution in uploads location ~* ^/wp-content/uploads/.*\.(php|phtml|phar)$ { deny all; } # Hide sensitive files location ~* /(wp-config\.php|readme\.html|license\.txt|\.env|\.git) { deny all; } # Block XML-RPC if nothing uses it location = /xmlrpc.php { deny all; } ``` ### Everything else on the server - Serve everything over HTTPS and redirect HTTP to HTTPS. - Disable directory listing and make sure backups, SQL dumps and debug.log are never stored in a public directory. - Use SFTP or SSH keys, never plain FTP. - Isolate sites from each other: one compromised site on a shared account can infect every other site in the same account. How much of this you control depends on your hosting. Managed WordPress hosts handle much of it for you; on a VPS, it is your job. We compare the trade-offs in [Choosing Web Hosting](/blog/choosing-web-hosting-static-wordpress-vps/). ## Layer 5: HTTP security headers Security headers tell browsers to enforce protections on your behalf. They limit the impact of cross-site scripting, prevent clickjacking and control what information leaks to other sites. | | Header | Purpose | Typical starting value | Strict-Transport-Security | Forces HTTPS on future visits | max-age=31536000; includeSubDomains | Content-Security-Policy | Restricts where scripts and other resources can load from | Start with frame-ancestors 'self', then build up in report-only mode | X-Content-Type-Options | Stops MIME-type sniffing | nosniff | Referrer-Policy | Limits URL data sent to other sites | strict-origin-when-cross-origin | Permissions-Policy | Disables browser features you don't use | camera=(), microphone=(), geolocation=() | X-Frame-Options | Legacy clickjacking protection | SAMEORIGIN A full Content Security Policy is the most powerful header and the hardest to deploy on WordPress, because themes and plugins often inject inline scripts. Roll it out with Content-Security-Policy-Report-Only first, collect violations, then enforce. On WooCommerce checkout pages, where payment card skimming scripts are a real threat, a tight policy is especially valuable. ## Layer 6: Writing secure custom code If you or your agency write custom themes or plugins, most vulnerabilities come down to four habits. WordPress provides APIs for each, documented in the [Security section of the Common APIs Handbook](https://developer.wordpress.org/apis/security/): - **Check capabilities** with current_user_can() before doing anything privileged — being logged in is not authorization. - **Verify intent** with nonces to prevent cross-site request forgery. - **Validate and sanitize input** on the way in. - **Escape output late**, at the moment of printing, with the function that matches the context. ``` get_results( $wpdb->prepare( "SELECT id, total FROM {$wpdb->prefix}custom_orders WHERE status = %s LIMIT %d", 'pending', $limit ) ); wp_safe_redirect( admin_url( 'options-general.php?page=store-notice&updated=1' ) ); exit; } ); // 4. Escape late, by context printf( '
%s', esc_url( $link ), esc_attr( $title ), esc_html( $label ) ); ``` ## Layer 7: Firewalls, monitoring and backups ### Web application firewall A WAF filters malicious requests before they reach WordPress. Edge firewalls run at a CDN or proxy and stop traffic before it consumes your server's resources; plugin-based firewalls run inside WordPress and understand its context better but share the server's load. Either is a useful extra layer — and virtual patching can block a known exploit before you have applied the update. ### Monitoring and integrity checks - **Uptime and content monitoring** to notice defacements or spam injections quickly. - **File integrity checks**: wp core verify-checksums and wp plugin verify-checksums --all compare your files against the official versions on WordPress.org. - **Activity logging** of logins, role changes, plugin installs and settings changes, so you can reconstruct what happened. - **Search Console** security issue alerts, which often flag injected spam before visitors notice. ### Backups you have actually tested Backups are your last line of defence and the one that makes every other failure recoverable. Follow the 3-2-1 principle: at least three copies, on two different types of storage, with one off-site and outside the reach of your hosting account's credentials. Include both files and the database, keep enough history to restore from before an undetected infection, and — most importantly — test a restore regularly. A backup you have never restored is a hope, not a plan. **If your site has been hacked** - Take a snapshot of the compromised site for analysis before changing anything, then put the site into maintenance mode. - Change every password: WordPress users, hosting, SFTP/SSH, database, and any API keys stored on the site. Shuffle the salts. - Find the entry point (outdated plugin, stolen credentials, another site on the same account) — otherwise reinfection is likely. - Restore from a known-clean backup or replace core, plugins and themes with fresh copies, then review uploads and the database for injected content and rogue admin users. - Update everything, monitor closely, and request a review in Search Console if Google flagged the site. ## The condensed checklist **Key takeaways** - Update core, plugins, themes and PHP promptly; remove anything unused, abandoned or nulled. - Unique passwords, two-factor authentication and least-privilege roles for every user. - Disable file editing, force HTTPS for admin, keep debug output off and regenerate salts after incidents. - Correct file permissions, no PHP execution in uploads, sensitive files blocked, XML-RPC off if unused. - Add security headers and work towards a Content Security Policy, especially on checkout. - In custom code: check capabilities, verify nonces, sanitize input, escape output, prepare queries. - Run a WAF, monitor file integrity and activity, and keep tested, off-site backups. Security also intersects with SEO: a hacked site can be flagged in search results or deindexed, which is why we include HTTPS, server headers and clean indexation in our [technical SEO checklist](/blog/technical-seo-checklist-new-websites/). Online stores carry extra responsibility because they handle customer data; the same plugin discipline that keeps them secure also keeps them fast, as covered in our [WooCommerce performance guide](/blog/woocommerce-performance-optimization/). ## Conclusion: make security a routine None of the layers in this checklist is difficult on its own. What makes WordPress sites vulnerable is that security tasks are easy to postpone: an update skipped here, a former contractor's admin account left active there, a backup nobody has tested. Layered defences, applied consistently, turn most attacks into non-events — and make the rare successful one recoverable. If you would rather not carry that routine yourself, our [Website Care & Maintenance Plan](/service/website-care-maintenance-plan/) handles updates, monitoring, off-site backups and security hardening every month. Building something new? Our [WordPress Website Development](/service/wordpress-website-development/) service ships with these defences in place from day one. [Contact us](/contact-us/) and tell us about your site. ## FAQ **Q:** Is WordPress secure enough for a business website? **A:** Yes, when it is maintained properly. WordPress core has a dedicated security team and automatic security releases. Most compromises come from outdated or abandoned plugins and themes, weak or reused passwords and poor hosting configuration, all of which you can control. **Q:** Do I need a security plugin? **A:** A security plugin can help with login protection, firewall rules and file change monitoring, but it is not a substitute for updates, strong authentication, sensible server configuration and backups. Choose one well-maintained tool rather than stacking several that overlap. **Q:** Should I disable XML-RPC? **A:** If nothing on your site uses it, yes. XML-RPC is a common target for brute-force login attempts. Some tools, such as certain mobile apps and older integrations, still rely on it, so check first; most modern integrations use the REST API with application passwords instead. **Q:** How often should I back up my WordPress site? **A:** Match backup frequency to how often the site changes. A brochure site may be fine with daily backups, while a busy WooCommerce store needs frequent database backups. Always keep copies off the server and test restores regularly. **Q:** What should I do first if my WordPress site is hacked? **A:** Take a fresh backup of the compromised state for analysis, put the site into maintenance mode, and change all passwords and keys. Then identify the entry point, clean or restore from a known-good backup, update everything, and monitor closely afterwards. --- # Modern PHP 8: Features That Changed How We Build Web Apps URL: https://hiddlins.com/blog/modern-php-8-features/ Published: 2026-06-24 · Updated: 2026-06-24 If your mental image of PHP was formed by WordPress plugins from 2012, modern PHP will surprise you. Across six releases — 8.0 in 2020 through 8.5 in late 2025 — the language gained named arguments, enums, readonly classes, property hooks, asymmetric visibility and, most recently, a pipe operator. The result is code that is shorter, safer and much easier for static analysis tools to understand. This guide walks through the features that changed how we design web applications, release by release, and finishes with a practical approach to upgrading legacy code. ## Why PHP 8 matters, and which version to run Two things make the PHP 8 series a turning point. First, the type system matured: union, intersection, DNF, never, standalone null/false/true and typed class constants allow you to describe almost any contract precisely. Second, the language removed ceremony: constructor property promotion, match, enums and property hooks eliminate whole categories of boilerplate. Running a supported version also matters for security. Each PHP branch gets two years of active support followed by two years of security-only fixes. According to the official [supported versions page](https://www.php.net/supported-versions.php), the status in October 2026 is: | | Branch | Released | Active support until | Security fixes until | Status (Oct 2026) | 8.0 | Nov 2020 | — | Nov 2023 | End of life | 8.1 | Nov 2021 | — | 31 Dec 2025 | End of life | 8.2 | Dec 2022 | 31 Dec 2024 | 31 Dec 2026 | Security only, ending soon | 8.3 | Nov 2023 | 31 Dec 2025 | 31 Dec 2027 | Security only | 8.4 | Nov 2024 | 31 Dec 2026 | 31 Dec 2028 | Active | 8.5 | Nov 2025 | 31 Dec 2027 | 31 Dec 2029 | Active If your site still runs on PHP 7.x, 8.0 or 8.1, it is running on software that no longer receives security patches from the PHP project. That is one of the first things we check in any [WordPress security review](/blog/wordpress-security-hardening/). ## PHP 8.0: the foundation PHP 8.0 was the biggest single jump in the language's modern history. The features we use daily: - **Constructor property promotion** declares and assigns properties straight from the constructor signature. - **Named arguments** make calls self-documenting and let you skip optional parameters. - **Union types** such as int|string, plus the mixed and static return types. - **The match expression**: strict comparison, no fall-through, returns a value and throws UnhandledMatchError if nothing matches. - **The nullsafe operator**?-> short-circuits a chain when a value is null. - **Attributes**, native structured metadata replacing docblock annotations. - **Quality-of-life additions**: str_contains(), str_starts_with(), str_ends_with(), throw as an expression, WeakMap and saner string-to-number comparisons. ``` amountCents >= 1_000_00 => 'large', $invoice->amountCents >= 100_00 => 'medium', default => 'small', }; $country = $invoice->customer?->address?->country ?? 'unknown'; ``` PHP 8.0 also introduced a JIT compiler. It is impressive for CPU-bound work, but typical web requests are dominated by database and network I/O, so for most sites OPcache — not the JIT — remains the performance feature that matters. ## PHP 8.1: enums, readonly and fibers PHP 8.1 delivered the feature many developers had wanted for years: **native enumerations**. Enums replace class constants and magic strings with a closed set of values the type system understands. Backed enums map cleanly to database columns and API payloads, and they can carry methods and implement interfaces. ``` 'Awaiting payment', self::Paid => 'Paid', self::Shipped => 'On its way', self::Cancelled => 'Cancelled', }; } public function canBeRefunded(): bool { return in_array($this, [self::Paid, self::Shipped], true); } } $status = OrderStatus::from($row['status']); // throws on unknown value $maybe = OrderStatus::tryFrom($input) ?? OrderStatus::Pending; ``` Also in 8.1: - **Readonly properties** can be initialized once and never modified — ideal for value objects. - **First-class callable syntax**: strlen(...) or $this->handle(...) creates a closure without string-based callables. - **new in initializers** allows objects as default parameter values. - **Pure intersection types** (Countable&Iterator) and the never return type. - **Fibers**, a low-level primitive that async libraries use to implement non-blocking I/O without callback pyramids. - **array_is_list()** and final class constants. ## PHP 8.2: readonly classes and stricter objects PHP 8.2 built on 8.1's foundations. **Readonly classes** make every declared property readonly with one keyword, which makes immutable data transfer objects trivial to write. **Disjunctive Normal Form (DNF) types** combine unions and intersections, such as (Countable&Iterator)|null, and null, false and true became usable as standalone types. ``` currency !== $this->currency) { throw new InvalidArgumentException('Currency mismatch'); } return new self($this->amountCents + $other->amountCents, $this->currency); } } ``` The change with the biggest real-world impact was the **deprecation of dynamic properties**. Assigning an undeclared property on an object now raises a deprecation notice unless the class opts in with #[\AllowDynamicProperties]. Older WordPress plugins relied on this heavily, and these notices are often the first thing that floods the logs after a PHP upgrade. PHP 8.2 also added the Random extension with a proper object-oriented API, constants in traits, and the #[\SensitiveParameter] attribute, which redacts values such as passwords from stack traces. ## PHP 8.3: safer refactoring PHP 8.3 was a smaller release focused on correctness and refactoring safety: - **Typed class constants**: const string PREFIX = 'inv_'; prevents child classes from changing a constant's type. - **The #[\Override] attribute** makes PHP throw an error if a method marked as an override does not actually override a parent or interface method — catching typos and silent breakage when a parent method is renamed. - **Dynamic class constant fetch**: Config::{$name}. - **Readonly properties can be re-initialized inside __clone()**, which enables proper deep cloning of immutable objects. - **json_validate()** checks JSON syntax without decoding it into memory, plus mb_str_pad() and new Randomizer methods. ``` email = $value; } } // Virtual property: computed, no storage public string $displayName { get => trim("{$this->firstName} {$this->lastName}"); } // Anyone can read, only this class can write public private(set) int $loyaltyPoints = 0; public function __construct( public string $firstName, public string $lastName, string $email, ) { $this->email = $email; } } ``` Other notable 8.4 additions from the [official release notes](https://www.php.net/releases/8.4/en.php): - **new without parentheses**: new Request()->withHeader(...). - **Array helpers**: array_find(), array_find_key(), array_any() and array_all(). - **A standards-compliant HTML5 parser** via Dom\HTMLDocument, a major improvement for scraping and content processing. - **#[\Deprecated]** for your own functions and constants, lazy objects for frameworks, BcMath\Number, mb_trim() and driver-specific PDO subclasses. - **Implicitly nullable parameters are deprecated**: write ?Type $x = null instead of Type $x = null. ## PHP 8.5: the pipe operator and friends PHP 8.5, released on 20 November 2025, continues the trend toward expressive, functional-friendly code. Its [release announcement](https://www.php.net/releases/8.5/en.php) highlights: - **The pipe operator |>**, which passes a value through a chain of callables left to right instead of nesting calls inside out. - **Clone with**: clone($this, ['alpha' => $alpha]) simplifies "wither" methods on readonly classes. - **A built-in URI extension** for parsing and modifying URLs according to RFC 3986 and the WHATWG URL standard. - **#[\NoDiscard]**, which warns when a function's important return value is ignored. - **array_first() and array_last()**, plus closures and first-class callables in constant expressions and backtraces for fatal errors. ``` trim(...) |> (fn (string $s) => preg_replace('/[^a-z0-9]+/i', '-', $s)) |> strtolower(...) |> (fn (string $s) => trim($s, '-')); ``` ## How modern PHP changes application design Individually, these are syntax improvements. Together, they shift how we structure applications: - **Value objects become the default.** Readonly classes, promotion and clone-with make small immutable types like Money, EmailAddress or Sku cheap to write, which pushes validation to the edges of the system. - **Enums replace stringly-typed state.** Order statuses, user roles and payment methods become exhaustive, and match forces you to handle every case. - **Static analysis gets dramatically better.** Tools like PHPStan and Psalm can verify far more when types live in the code rather than in comments, and many bugs are caught before code ever runs. - **Less framework magic is needed.** Attributes give routing, validation and serialization a native home; property hooks remove the need for magic __get() and __set(). ### Attributes in practice Attributes deserve a closer look because they changed how frameworks and libraries are configured. Before PHP 8, metadata lived in docblock comments that had to be parsed as strings — a typo was silently ignored. Attributes are real syntax: they are validated by the parser, can be namespaced and autoloaded like classes, and are read through the Reflection API. Here is a minimal router that discovers routes from attributes: ``` getMethods() as $method) { foreach ($method->getAttributes(Route::class) as $attribute) { $route = $attribute->newInstance(); $router->add($route->method, $route->path, [ProductController::class, $method->name]); } } ``` The same mechanism powers validation rules, serialization hints, dependency injection configuration and the built-in engine attributes such as #[\Override], #[\Deprecated], #[\SensitiveParameter] and #[\NoDiscard]. Because attributes are code, your IDE can autocomplete them and refactoring tools can rename them safely. ### Errors instead of silent failures A quieter but important shift runs through the whole 8.x series: many situations that used to produce warnings or return false now throw TypeError or ValueError. Internal functions validate their arguments consistently, comparisons between numbers and non-numeric strings behave sensibly, and match throws when no arm matches. Code becomes more predictable — and bugs that previously hid in the logs surface immediately during testing. **Tip** - Adopt features where they reduce risk first: enums for state, readonly value objects for money and identifiers, #[\Override] on every overriding method. - Raise your static analysis level gradually; a baseline file lets you fix new code strictly while legacy code catches up. ## Upgrading legacy code and WordPress sites Most upgrade pain comes from a handful of predictable changes: dynamic property deprecations, stricter type handling in internal functions, removed functions, and deprecations such as implicitly nullable parameters. A safe process looks like this: - **Inventory.** List your PHP version, extensions, Composer dependencies, plugins and themes. - **Scan statically.** PHPCompatibility rules for PHP_CodeSniffer and PHPStan flag many incompatibilities without running the code. - **Automate the mechanical work.** Rector can apply many version upgrades automatically, such as adding nullable types or promoting constructor properties. - **Test on staging** with error_reporting(E_ALL) and logging enabled; deprecation notices are your to-do list. - **Upgrade one minor version at a time** when jumping several versions, so each failure has a clear cause. - **Switch production**, keep logs under watch for a week, and make sure OPcache is enabled and sized appropriately. For WordPress and WooCommerce, core itself runs on current PHP 8 releases; the risk sits in plugins and themes, especially abandoned ones. Upgrading PHP usually also improves server response times, which helps your [Core Web Vitals](/blog/core-web-vitals-guide/) and keeps busy stores responsive, as discussed in our [WooCommerce performance guide](/blog/woocommerce-performance-optimization/). If your host makes it hard to choose a PHP version, that is a sign it may be time to revisit [your hosting choice](/blog/choosing-web-hosting-static-wordpress-vps/). **Key takeaways** - Run PHP 8.4 or 8.5 for new work; anything below 8.2 no longer receives security fixes. - 8.0 and 8.1 brought the essentials: promotion, named arguments, match, enums and readonly properties. - 8.2 to 8.4 made immutability and encapsulation first-class: readonly classes, #[\Override], property hooks, asymmetric visibility. - 8.5 adds the pipe operator, clone-with and a native URI API. - Upgrade with static analysis, Rector and a staging environment — not by flipping the switch in production. ## Conclusion: PHP has grown up Modern PHP is a typed, expressive language with a predictable release cycle and excellent tooling. Taking advantage of it means more than changing a version number: it means modelling your domain with enums and value objects, letting static analysis catch mistakes early, and keeping your runtime on a supported branch. Whether you are planning a new platform or modernizing an ageing codebase, our [Custom Web Application Development](/service/custom-web-application-development/) service builds on current PHP with these practices from day one. If you simply need your existing site kept on a supported, secure PHP version, our [Website Care & Maintenance Plan](/service/website-care-maintenance-plan/) covers it. [Contact us](/contact-us/) to discuss your project. ## FAQ **Q:** Which PHP version should I use in 2026? **A:** For new projects, use PHP 8.4 or 8.5, both of which are in active support. PHP 8.2 receives only security fixes until the end of 2026 and PHP 8.1 and older no longer receive any updates, so sites on those versions should be upgraded. **Q:** Is it safe to upgrade a WordPress site to PHP 8.4? **A:** WordPress core runs on current PHP 8 releases, but compatibility depends on your plugins and theme. Test on a staging copy with error logging enabled, check deprecation notices, update or replace incompatible extensions, and then switch production. **Q:** Does the PHP JIT make websites faster? **A:** The JIT compiler mainly helps CPU-heavy workloads such as numerical computation or image processing. Typical web requests spend most of their time on database queries and I/O, so the JIT rarely makes a noticeable difference there, while OPcache remains essential. **Q:** What are property hooks in PHP 8.4? **A:** Property hooks let you attach get and set logic directly to a class property, so you can validate or transform values and define computed properties without writing separate getter and setter methods. They work together with asymmetric visibility, such as public private(set). --- # Modern JavaScript Without the Bloat: When You Don’t Need a Framework URL: https://hiddlins.com/blog/vanilla-javascript-without-frameworks/ Published: 2026-06-14 · Updated: 2026-06-14 For a decade, starting a new frontend project meant picking a framework first and asking questions later. In 2026 that reflex deserves a second look. Browsers now ship native modal dialogs, popovers, ES modules, import maps, view transitions, container queries and the :has() selector — features that used to justify pulling in a library. For a large share of websites, especially content sites, marketing pages and stores, plain "vanilla" JavaScript layered on server-rendered HTML is faster to load, simpler to maintain and easier to make accessible. This article shows what the platform gives you, the patterns we use to keep vanilla code organized, and an honest framework for deciding when a framework really is the better tool. ## The real cost of defaulting to a framework Frameworks solve real problems: predictable rendering, component composition and state management at scale. But every one of them has costs that are easy to ignore at the start of a project: - **JavaScript is the most expensive byte on the web.** Unlike an image, script must be downloaded, parsed, compiled and executed on the main thread. On mid-range phones, that execution time is what users feel. - **Hydration doubles the work.** Server-rendered framework pages typically send HTML and the code to recreate it, then re-run components in the browser to attach behaviour. That burst of work lands exactly when users begin to interact, which is bad news for [Interaction to Next Paint](/blog/core-web-vitals-guide/). - **Dependency churn.** Major versions, router rewrites and ecosystem shifts create maintenance work that has nothing to do with your product. - **Accessibility is not automatic.** Component libraries often reimplement native controls, and each reimplementation is a chance to get keyboard handling and semantics wrong. None of this means frameworks are bad. It means the decision should be made deliberately, based on how interactive the interface genuinely is. ## What the platform gives you now The single biggest change of recent years is how much UI behaviour has moved into HTML and CSS. MDN tracks cross-browser readiness using [Baseline](https://developer.mozilla.org/en-US/docs/Glossary/Baseline/Compatibility): "newly available" means a feature works in the latest versions of all major browsers, and "widely available" means it has done so for at least two and a half years. | | You need | Native solution | Library it often replaces | Modal window | with showModal() | Modal/lightbox plugins | Menus, tooltips, toasts | popover attribute | Dropdown and tooltip libraries | Accordion / FAQ |
and , with name for exclusive groups | Accordion scripts | Animated state changes | View Transition API | Page transition and animation libraries | HTTP requests | fetch() with AbortController | AJAX helper libraries | Dates, numbers, plurals | Intl formatters | Date and number formatting libraries | Query strings | URL and URLSearchParams | Query-string parsers | Deep copies | structuredClone() | Utility-library clone helpers | Scroll-triggered behaviour | IntersectionObserver | Scroll-spy and lazy-load scripts | Form validation | Constraint Validation API | Validation plugins | Parent and component-aware styling | CSS :has() and container queries | JavaScript that toggles layout classes | Modular code | ES modules and import maps | Module loaders and some build steps The [Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) is a good example of how much this matters. A dropdown menu needs top-layer rendering, light dismiss (closing on outside click or Escape) and correct focus behaviour. With popover and popovertarget, you get all of that from two attributes and no script. ``` ``` ### Modal dialogs without a library Modals are the classic example of a component that is deceptively hard to build well: focus must move into the dialog, the rest of the page must become inert, Escape must close it and focus must return to the trigger afterwards. The native element handles all of this when opened with showModal(). The only script you write is the part that is specific to your product: ``` const dialog = document.getElementById('newsletter-dialog'); document.querySelector('[data-open-newsletter]') .addEventListener('click', () => dialog.showModal()); // A
inside the dialog closes it on submit; // returnValue tells you which button was used. dialog.addEventListener('close', () => { if (dialog.returnValue === 'subscribe') trackSignup(); }); ``` Native elements also bring correct semantics for free, which is why we consider [semantic HTML](/blog/semantic-html-seo-accessibility/) the first layer of any interface. ## Start with HTML, then enhance The architecture that makes vanilla JavaScript scale is progressive enhancement: the server renders complete, working HTML, and scripts add behaviour on top. A filter form still submits and reloads without JavaScript; with JavaScript, it updates results in place. Links still navigate; with JavaScript, they might prefetch or animate. In practice we wire behaviour with data- attributes and a single delegated listener, so new markup inserted later works automatically and there is no per-element setup to forget: ``` // One listener handles every [data-action] element on the page, // including elements added after load. const actions = { 'copy-code': (el) => navigator.clipboard.writeText( document.getElementById(el.dataset.target).textContent ), 'toggle-theme': () => document.documentElement.classList.toggle('theme-dark'), }; document.addEventListener('click', (event) => { const trigger = event.target.closest('[data-action]'); if (!trigger) return; const handler = actions[trigger.dataset.action]; if (handler) { event.preventDefault(); handler(trigger, event); } }); ``` This pattern keeps HTML as the source of truth, keeps behaviour discoverable (search the codebase for data-action="copy-code") and works well in CMS environments like WordPress, where markup comes from many templates and plugins. ## Managing state without a framework "State management" sounds like it requires a library, but most UI state on content sites is small: a cart count, a selected filter, an open panel. For shared state, a tiny store built on the native EventTarget class goes a long way: ``` // store.js — a minimal observable store export class Store extends EventTarget { #state; constructor(initial) { super(); this.#state = structuredClone(initial); } get state() { return this.#state; } update(patch) { this.#state = { ...this.#state, ...patch }; this.dispatchEvent(new CustomEvent('change', { detail: this.#state })); } } // cart.js import { Store } from './store.js'; export const cart = new Store({ count: 0 }); // header-badge.js import { cart } from './cart.js'; const badge = document.querySelector('[data-cart-count]'); cart.addEventListener('change', (e) => { badge.textContent = e.detail.count; }); ``` Components subscribe only to what they need and update only their own DOM. If you find yourself building derived state, undo stacks and complex synchronization on top of this, that is a strong signal you have outgrown vanilla — more on that below. ## Rendering and DOM updates, safely The two classic pitfalls of hand-written rendering are security and performance. Building HTML strings from data and assigning them to innerHTML invites cross-site scripting if any value comes from users or an API. The