<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Illucrum blog]]></title><description><![CDATA[Practical SEO for businesses that want growth, not jargon. Audits, rankings, technical fixes — explained plainly by the team at Illucrum.]]></description><link>https://blog.illucrum.com</link><image><url>https://cdn.hashnode.com/uploads/logos/6938690abe359741ad261496/75042e2a-e853-42f9-ba9e-11f02f0b1aff.png</url><title>Illucrum blog</title><link>https://blog.illucrum.com</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 10 Apr 2026 12:19:00 GMT</lastBuildDate><atom:link href="https://blog.illucrum.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Shopify SEO: 7 Issues the Platform Creates]]></title><description><![CDATA[Shopify makes launching an online store fast. It handles hosting, SSL, sitemaps, and basic mobile responsiveness out of the box. What it does not handle well is the structural SEO work that determines]]></description><link>https://blog.illucrum.com/shopify-seo</link><guid isPermaLink="true">https://blog.illucrum.com/shopify-seo</guid><category><![CDATA[shopify]]></category><category><![CDATA[SEO]]></category><category><![CDATA[shopify seo]]></category><dc:creator><![CDATA[Szymon Kokot]]></dc:creator><pubDate>Mon, 06 Apr 2026 07:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6938690abe359741ad261496/aea8d1d7-a1bc-4071-8f62-dfcfe4353d2a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Shopify makes launching an online store fast. It handles hosting, SSL, sitemaps, and basic mobile responsiveness out of the box. What it does not handle well is the structural SEO work that determines whether your store actually appears in search results. The platform's rigid URL system, automatic duplicate content generation, and limited control over indexing create problems that most store owners never notice until their rankings stall.</p>
<p>This is not a general SEO guide. It is specifically about the issues Shopify introduces and what you can do about them. If you are running a Shopify store and organic traffic is not where it should be, at least one of these is probably why.</p>
<p><strong>In short:</strong> Shopify is a strong e-commerce platform, but its default settings create duplicate content, bloated indexes, and thin pages that hurt search rankings. Fixing these platform-specific issues is the fastest path to better organic performance for most Shopify stores.</p>
<h2>1. Duplicate Product URLs</h2>
<p>This is Shopify's most persistent SEO problem, and it is baked into the platform's architecture. When a product belongs to more than one collection, Shopify creates a separate URL for each collection path.</p>
<p>A single pair of running shoes might be accessible at <code>/products/trail-runner-pro</code>, <code>/collections/mens-shoes/products/trail-runner-pro</code>, and <code>/collections/new-arrivals/products/trail-runner-pro</code>. All three URLs serve identical content.</p>
<p>Shopify adds canonical tags that point to the <code>/products/</code> version, which helps. But the internal links on your site, particularly from collection pages, often point to the collection-based URL rather than the canonical one. This sends mixed signals to search engines about which version matters and splits your link equity across multiple pages.</p>
<p>The fix has two parts. First, audit your internal links to ensure they point to the canonical <code>/products/</code> URL, not the collection path. This usually requires editing your theme's Liquid templates. Second, use Google Search Console to verify that the correct URLs are being indexed and that duplicate versions are not appearing in search results.</p>
<h2>2. Tag Pages and Index Bloat</h2>
<p>Shopify generates a new page every time you use tags to filter products within a collection. If you sell clothing and use tags like "cotton," "long-sleeve," "red," and "summer," each combination creates a unique, indexable URL.</p>
<p>These tag pages carry the same products as your main collection page, with no way to add unique titles, descriptions, or introductory content through Shopify's standard admin. From Google's perspective, they are thin, duplicate pages. A store with 20 collections and 10 tags per collection can accidentally generate 200 near-identical pages competing with your actual category pages.</p>
<p>The most reliable fix is adding a noindex directive to tag pages. This keeps them functional for shoppers (they can still filter products) while preventing search engines from treating them as separate pages. You can do this by adding conditional logic to your theme's <code>&lt;head&gt;</code> section that inserts a noindex meta tag when the URL contains a <code>/tagged/</code> path.</p>
<p>If specific tag pages genuinely target unique keywords (for example, a "vegan leather" tag page in a handbag store), you can selectively allow indexing for those pages while noindexing the rest. But this is the exception, not the rule.</p>
<h2>3. Thin Product and Collection Content</h2>
<p>Shopify's content editing tools are functional but basic. The product description field is a simple rich text editor, and collection pages default to displaying a product grid with minimal or no descriptive text. Many store owners leave these fields empty or paste in the manufacturer's default description.</p>
<p>Both choices hurt search rankings. Empty or near-identical descriptions mean Google has no unique content to index on these pages. When the same manufacturer description appears on your store and 30 competitors' stores, none of you will rank well for it.</p>
<p>For product pages, write original descriptions of at least 150 to 300 words per product. Lead with benefits and use cases rather than technical specifications. Include your primary keyword within the first 100 words, and add secondary terms naturally throughout.</p>
<p>For collection pages, add 200 to 300 words of unique descriptive copy above or below the product grid. This is the single most underrated optimisation for Shopify stores. Collection pages can rank for high-volume category keywords ("women's running shoes," "organic skincare") that individual product pages cannot.</p>
<h2>4. Rigid URL Structure</h2>
<p>Shopify enforces a fixed URL structure that you cannot change. Products always live under <code>/products/</code>, collections under <code>/collections/</code>, blog posts under <code>/blogs/[blog-name]/</code>, and pages under <code>/pages/</code>. There is no way to create a custom URL hierarchy like <code>/shoes/running/trail-runner-pro/</code>.</p>
<p>This is not a serious ranking disadvantage on its own. Google can rank pages regardless of their URL path. But it does mean your URLs provide less contextual information to search engines than a flexible platform like WooCommerce would allow.</p>
<p>Where this becomes a practical problem is in breadcrumb navigation. Shopify's default breadcrumbs are naturally shallow because there is no true parent-child category relationship in the URL structure. You can implement breadcrumb schema markup to help Google understand your site hierarchy even though the URLs don't reflect it, but this requires manual coding in your theme.</p>
<p>Focus your effort on what you can control: make URL slugs short and descriptive (edit the "URL and handle" field for every product and collection), and use internal linking to establish the relationships between pages that the URL structure cannot express.</p>
<h2>5. Page Speed and Theme Bloat</h2>
<p>Shopify's hosted infrastructure is fast by default. The problems come from what store owners add on top of it: heavy themes, too many apps, unoptimised images, and third-party scripts.</p>
<p>Every Shopify app you install adds JavaScript and CSS to your pages. A store with 15 apps can easily add two to three seconds of load time. Many of these apps continue loading their scripts on every page even when their functionality is only needed on one.</p>
<p>Themes are another factor. A theme that looks impressive in the Shopify Theme Store might have render-blocking JavaScript, unoptimised image delivery, and poor Core Web Vitals scores. According to industry data, a large majority of Shopify stores load slower than Google's recommended thresholds.</p>
<p>The fixes here are straightforward but require discipline. Audit your installed apps and remove anything you are not actively using. Compress all product images before uploading (tools like TinyPNG or Squoosh work well). Choose a lightweight theme, or have your current theme audited for performance issues. Use lazy loading for images below the fold.</p>
<h2>6. Missing or Generic Structured Data</h2>
<p>Shopify does not include rich schema markup by default. Some themes add basic Product schema, but many do not include critical fields like review ratings, availability, price currency, or brand information.</p>
<p>Without proper structured data, your products cannot appear in Google's rich results (the listings that show star ratings, prices, and stock status directly in search results). They also cannot appear in Google Shopping's free product listings. In 2026, with AI-generated search overviews pulling structured data to answer product queries, missing schema means your store is invisible in an increasing share of search results.</p>
<p>The implementation path depends on your technical comfort level. You can add Product schema directly to your theme's Liquid templates, use a Shopify app like Smart SEO or JSON-LD for SEO, or have a developer implement it. Whichever method you choose, validate the markup afterwards using Google's Rich Results Test. Broken schema can actually prevent your pages from displaying correctly, so validation is not optional.</p>
<p>At minimum, every product page should include: product name, description, brand, SKU or GTIN, price, currency, availability status, and aggregate review rating (if you have reviews). Collection pages benefit from FAQ schema if you add descriptive content that answers common questions about the product category.</p>
<h2>7. Limited Blog Functionality</h2>
<p>Shopify includes a built-in blog, but it is basic compared to WordPress or dedicated content platforms. You get a title, a rich text body, tags, and a featured image. There is no table of contents generation, no advanced layout options, no native support for FAQ schema, and limited control over URL structure.</p>
<p>This matters because content marketing is how online stores capture informational and long-tail keywords that product pages cannot target. "How to choose running shoes for flat feet" or "best materials for kitchen knives" are searches that a blog post can rank for and that a product page never will.</p>
<p>The blog limitation is a genuine constraint, but it is not a reason to skip content entirely. You can work around most of the formatting issues by editing HTML within blog posts, and FAQ schema can be added to your theme's blog template. Some stores opt for a separate blog on a subdomain (using WordPress or a platform like Hashnode) to get more flexibility, though this introduces additional complexity around domain authority and link equity.</p>
<p>What matters more than the platform is consistency. A Shopify blog with one well-written, keyword-targeted post per month will outperform no blog at all. Start with topics your customers actually search for: buying guides, size guides, material comparisons, care instructions. Each post should link to relevant product and collection pages, creating the internal linking network that both users and search engines rely on.</p>
<h2>Frequently Asked Questions</h2>
<h3>Is Shopify good for SEO?</h3>
<p>Shopify handles many SEO fundamentals well: SSL, mobile responsiveness, XML sitemaps, and canonical tags are all included by default. But the platform's rigid URL structure, duplicate content generation, and limited technical control create issues that require manual fixes. Shopify is a capable SEO platform, but it is not a hands-off one.</p>
<h3>Does changing my Shopify theme affect SEO?</h3>
<p>It can. A new theme may change your page load speed, heading structure, schema markup, and mobile layout. Before switching themes, benchmark your current Core Web Vitals scores and review the new theme's code quality. After switching, re-validate your structured data and check Google Search Console for any new crawl errors.</p>
<h3>How do I fix duplicate content on Shopify?</h3>
<p>Shopify's duplicate content comes primarily from two sources: products appearing in multiple collections (creating multiple URLs) and tag pages. For collection-based duplicates, ensure internal links point to the canonical <code>/products/</code> URL. For tag pages, add a noindex directive to your theme's <code>&lt;head&gt;</code> section for any URL containing <code>/tagged/</code>.</p>
<h3>Do I need a Shopify SEO app?</h3>
<p>An SEO app can help with bulk editing meta tags, generating structured data, and automating image alt text. If you have hundreds of products, the time savings are significant. Smart SEO and JSON-LD for SEO are well-regarded options. Avoid installing multiple SEO apps, as they often conflict with each other and add unnecessary load time.</p>
<h3>How often should I audit my Shopify store's SEO?</h3>
<p>A full audit once or twice per year is a reasonable starting point. Between audits, monitor Google Search Console monthly for crawl errors, indexing issues, and keyword performance changes. Any time you add a significant number of products, change themes, or install new apps, check your technical SEO metrics to catch regressions early.</p>
<h2>What to Do Next</h2>
<p>Shopify's SEO challenges are real, but they are also well-understood and fixable. Most stores underperform in search not because the platform is fundamentally limited, but because these platform-specific issues go unaddressed.</p>
<p>If your store's organic traffic is flat or declining, the issues above are the first place to look. An <a href="https://illucrum.com/audits/ecommerce-seo-audit">e-commerce SEO audit</a> built specifically for Shopify will identify exactly which of these problems exist on your store and prioritise fixes by impact. If you already know what needs fixing, the optimisation work can be handled for you.</p>
]]></content:encoded></item><item><title><![CDATA[E-Commerce SEO: What Online Stores Get Wrong]]></title><description><![CDATA[Most online stores treat SEO as something you bolt on after launch. Add a few keywords to product titles, install an SEO plugin, and hope for the best. The problem is that e-commerce sites face struct]]></description><link>https://blog.illucrum.com/ecommerce-seo</link><guid isPermaLink="true">https://blog.illucrum.com/ecommerce-seo</guid><category><![CDATA[ecommerce]]></category><category><![CDATA[SEO]]></category><category><![CDATA[ecommerce seo]]></category><dc:creator><![CDATA[Szymon Kokot]]></dc:creator><pubDate>Mon, 30 Mar 2026 07:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6938690abe359741ad261496/14abf8f8-dc4a-4c92-92ce-03400f7a3c50.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most online stores treat SEO as something you bolt on after launch. Add a few keywords to product titles, install an SEO plugin, and hope for the best. The problem is that e-commerce sites face structural challenges that a generic SEO checklist will never catch. Duplicate product URLs, bloated tag pages, thin category content, slow load times caused by image-heavy catalogues; these are not edge cases. They are the default state of most online stores, and they quietly suppress rankings for months before anyone notices.</p>
<p>This guide covers the areas where e-commerce SEO differs from standard website optimisation, why those differences matter, and what to prioritise if your store is not getting the organic traffic it should.</p>
<p><strong>In short:</strong> E-commerce SEO is not generic SEO applied to a shop. Product pages, category architecture, structured data, and platform-specific technical issues all require a different approach. Stores that treat SEO as a technical discipline rather than an afterthought consistently outperform those relying on paid ads alone.</p>
<h2>Why Is E-Commerce SEO Different from Regular SEO?</h2>
<p>A typical business website might have 10 to 50 pages. An online store can have hundreds or thousands. That scale changes everything about how search engines crawl, index, and rank your content.</p>
<p>Three things make e-commerce SEO distinct. First, product pages generate duplicate content by default. A single product listed in three different collections creates three separate URLs with identical content. Search engines don't know which one to rank, so they often rank none of them well.</p>
<p>Second, category and tag pages can create index bloat. Every filter combination (size, colour, material, price range) can produce a unique URL. Left unmanaged, a store with 200 products might generate 2,000 indexable pages, most of them thin or near-identical.</p>
<p>Third, commercial intent keywords behave differently from informational ones. Someone searching "waterproof hiking boots size 42" is ready to buy. Someone searching "how to waterproof hiking boots" wants information. Your product pages and your blog content need to target these two groups separately, with different page types and different content strategies.</p>
<h2>Product Pages: Where Most Stores Lose Rankings</h2>
<p>Product pages are the commercial core of any online store, and they are where most SEO effort falls apart. The most common issue is copied manufacturer descriptions. If 30 other stores carry the same product with the same description, Google has no reason to rank yours above theirs.</p>
<p>Writing unique product descriptions takes time. For a store with 500 products, it is a genuine investment. But it is also the single most impactful on-page change most stores can make. Descriptions don't need to be long; 150 to 300 words per product is enough. What matters is that they are original, that they include the primary keyword naturally, and that they lead with benefits and specific use cases rather than a generic feature list.</p>
<p>Beyond descriptions, product pages need proper title tags (unique per product, under 60 characters), descriptive alt text on every image, and structured data markup. Product schema (name, price, availability, reviews) is what makes your products eligible for rich results in Google, including star ratings, prices, and stock status directly in search results.</p>
<h2>Category Pages: The Most Underestimated Asset</h2>
<p>Many store owners treat collection or category pages as simple product grids. A heading, a row of thumbnails, and nothing else. This is a missed opportunity.</p>
<p>Category pages target broader, higher-volume keywords. "Women's running shoes" gets far more searches than any individual shoe model. A category page with 200 to 300 words of well-written descriptive copy gives search engines the context they need to understand what the page is about and rank it accordingly.</p>
<p>Effective category page optimisation goes beyond adding text. It includes clear heading structure, internal links to related categories and subcategories, and a logical URL hierarchy. A flat structure where every category sits at the same level makes it harder for both users and search engines to understand how your products relate to each other.</p>
<p>The ideal site architecture for an online store follows a simple rule: every product should be reachable within three clicks from the homepage. Homepage links to main categories, categories link to subcategories, subcategories link to products. Breadcrumb navigation reinforces this hierarchy and gives search engines an explicit map of your site's structure.</p>
<h2>Technical SEO for E-Commerce: The Invisible Foundation</h2>
<p>Technical SEO is where e-commerce sites accumulate the most damage without realising it. The issues are rarely visible to the store owner, but they are very visible to search engines.</p>
<p><strong>Duplicate URLs:</strong> Most e-commerce platforms create multiple URLs for the same product when it belongs to more than one collection. Without canonical tags pointing to the preferred version, you split your ranking power across duplicate pages. This is platform-specific; Shopify handles it differently from WooCommerce, which handles it differently from Magento. Each requires a different fix.</p>
<p><strong>Tag and filter pages:</strong> When customers use filters (size, colour, price range), each combination can generate a unique URL. These pages usually contain the same products as the parent category, just in a different order. If they are indexed, they dilute your site's authority across dozens or hundreds of near-identical pages. The fix is typically a combination of canonical tags, noindex directives, and careful use of robots.txt.</p>
<p><strong>Page speed:</strong> Online stores are inherently heavier than content websites. Product images, review widgets, recommendation carousels, chat plugins, and analytics scripts all add load time. Research consistently shows that every additional second of load time costs measurable conversion rate points. Google's Core Web Vitals remain a ranking factor, and most e-commerce themes underperform on mobile without deliberate optimisation.</p>
<p><strong>Pagination:</strong> Stores with large catalogues need pagination that search engines can follow. If Google can only see the first page of a 20-page category, the products on pages 2 through 20 may never get indexed.</p>
<h2>E-Commerce Keyword Strategy: Think in Layers</h2>
<p>Keyword research for an online store is not a single list. It works in layers that map to different page types.</p>
<p><strong>Product keywords</strong> are specific and high-intent: "Nike Air Zoom Pegasus 40 women's" or "Le Creuset 5.5 qt Dutch oven." These target product pages and often convert at the highest rate because the searcher already knows what they want.</p>
<p><strong>Category keywords</strong> are broader: "women's running shoes" or "cast iron cookware." These target collection pages and capture shoppers who are browsing rather than buying a specific item.</p>
<p><strong>Long-tail and modifier keywords</strong> combine product types with qualifiers: "best running shoes for flat feet" or "lightweight Dutch oven for camping." These often work best as blog content that links to relevant product or category pages.</p>
<p><strong>Problem-solution keywords</strong> are informational: "how to season a Dutch oven" or "running shoes for plantar fasciitis." These attract top-of-funnel traffic through content marketing and build authority over time.</p>
<p>The mistake most stores make is targeting only one layer. They optimise product pages for product keywords and ignore everything else. A complete keyword strategy covers all four layers, with each page type serving a different stage of the buyer journey.</p>
<h2>Structured Data: Making Your Products Visible Beyond Blue Links</h2>
<p>In 2026, Google's search results for product queries are dominated by rich results: Shopping carousels, product panels with prices and reviews, image packs, and AI-generated overviews. Stores that implement structured data correctly appear in these features. Stores that don't are invisible in the most valuable parts of the results page.</p>
<p>At minimum, every product page should include Product schema with name, description, brand, price, currency, availability, and review ratings. This markup tells search engines exactly what is on the page and makes your products eligible for rich result display.</p>
<p>Beyond Product schema, stores should consider FAQ schema on category pages (for common questions about the product type), Breadcrumb schema (to show site hierarchy in search results), and Organisation schema on the homepage.</p>
<p>The setup is technical but not complex. Most e-commerce platforms support it either natively or through apps and plugins. The important thing is to validate your markup using Google's Rich Results Test after implementation; broken schema is worse than no schema because it can prevent your pages from appearing correctly.</p>
<h2>AI Search and Generative Engine Optimisation</h2>
<p>Google's AI Overviews now appear on a significant share of search results, and tools like ChatGPT, Perplexity, and Claude are increasingly used for product research. This does not require a separate strategy, but it does reinforce the importance of clear, well-structured content.</p>
<p>AI systems pull information from pages that are well-organised, factually specific, and authoritative. The same practices that drive traditional SEO rankings (unique content, structured data, clear headings, fast load times, strong backlink profiles) also make your store more likely to be cited in AI-generated answers.</p>
<p>The stores that will perform best in both traditional and AI-powered search are the ones that treat their content as a product in its own right: well-researched, clearly written, and structured for machines as much as for humans.</p>
<h2>Frequently Asked Questions</h2>
<h3>How long does it take for e-commerce SEO to show results?</h3>
<p>Most stores see measurable changes within three to six months, depending on the starting point. Technical fixes (page speed, duplicate content, schema markup) can produce faster gains because they remove existing barriers. Content and link-building strategies compound over time and typically show stronger results after six months.</p>
<h3>Is e-commerce SEO different for Shopify vs WooCommerce?</h3>
<p>The principles are the same, but the implementation differs significantly. Shopify has a rigid URL structure and auto-generates duplicate product URLs across collections. WooCommerce offers more flexibility but can suffer from plugin bloat and slower performance. Each platform has specific technical issues that require platform-aware solutions.</p>
<h3>Do I need a blog on my online store?</h3>
<p>A blog is the most effective way to target informational and long-tail keywords that product and category pages cannot. It builds topical authority, creates internal linking opportunities, and captures top-of-funnel traffic that may convert later. Stores without content marketing are limited to ranking for purely commercial terms, which are usually the most competitive.</p>
<h3>What is the most common e-commerce SEO mistake?</h3>
<p>Using manufacturer-provided product descriptions that are identical across dozens of other stores. This creates a duplicate content problem that is invisible to the store owner but obvious to search engines. Writing unique descriptions for even your top 50 products will have a measurable impact.</p>
<h2>Where to Start</h2>
<p>E-commerce SEO is not one task; it is a system of overlapping disciplines that compound when done well. If your store is not generating the organic traffic you expect, the issue is almost always in one of the areas covered above: product page content, category structure, technical health, or keyword coverage.</p>
<p>The most efficient starting point is an <a href="https://illucrum.com/audits/ecommerce-seo-audit">audit</a> that evaluates all of these areas against your specific platform and competitive landscape. Once you know what is actually holding your store back, you can prioritise fixes by impact rather than guessing. And if the fixes require more hands than you have, the implementation can be handled for you.</p>
]]></content:encoded></item><item><title><![CDATA[What Is an SEO Audit?]]></title><description><![CDATA[If your website is not bringing in the traffic or leads you expected, the first useful question is: why? An SEO audit answers that question. It is a structured review of your website across the factor]]></description><link>https://blog.illucrum.com/what-is-an-seo-audit</link><guid isPermaLink="true">https://blog.illucrum.com/what-is-an-seo-audit</guid><category><![CDATA[SEO]]></category><category><![CDATA[SEO audit]]></category><dc:creator><![CDATA[Szymon Kokot]]></dc:creator><pubDate>Mon, 23 Mar 2026 08:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6938690abe359741ad261496/7e46d953-aae3-43b0-9498-51778a5bc230.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If your website is not bringing in the traffic or leads you expected, the first useful question is: why? An SEO audit answers that question. It is a structured review of your website across the factors that determine whether Google shows it to the people searching for what you offer. This article explains what an audit actually covers, what it produces, and how to know whether your business needs one.</p>
<p><strong>In short:</strong> An SEO audit is a systematic review of your website's technical setup, content, keywords, backlinks, and user experience. It identifies the specific issues holding back your search visibility and delivers a prioritised list of what to fix, in what order, and why each fix matters to your business.</p>
<h2>What does an SEO audit actually check?</h2>
<p>A professional SEO audit covers several categories, each focused on a different aspect of how search engines evaluate your website. These are the main areas.</p>
<p><strong>Technical SEO</strong> looks at how well Google can access, crawl, and index your site. It covers page speed, mobile-friendliness, Core Web Vitals, HTTPS status, crawl errors, and whether your sitemap and robots.txt files are configured correctly. Technical issues are often invisible to visitors but can quietly prevent your pages from appearing in search results at all.</p>
<p><strong>On-page SEO</strong> assesses the content and HTML elements on your individual pages. This includes title tags, meta descriptions, heading structure, keyword usage, content quality, and internal links. On-page SEO is where many SME websites lose ground; a page might rank on page two instead of page one simply because its title tag is poorly written or its headings don't match what people actually search for.</p>
<p><strong>Keyword strategy</strong> evaluates whether your site targets the right search terms and whether your content matches the intent behind those terms. A law firm writing articles about "legal precedent analysis" when potential clients are searching "do I need a lawyer for a lease dispute" is a keyword strategy problem. The audit checks for gaps like this.</p>
<p><strong>Backlink profile</strong> reviews the external links pointing to your site. Backlinks remain one of Google's strongest ranking signals. The audit assesses how many you have, how authoritative they are, and whether any are toxic (spammy or penalised links that could be hurting your rankings rather than helping them).</p>
<p><strong>Competitor analysis</strong> benchmarks your site against the businesses ranking above you. It reveals what they are doing that you are not, where they are weaker than you, and where the realistic opportunities lie. This is not about copying competitors; it is about understanding the landscape you are competing in.</p>
<p><strong>User experience and conversion</strong> covers how visitors interact with your site once they arrive. Page layout, call-to-action visibility, navigation clarity, mobile usability, and trust signals all affect whether a visitor becomes a customer. Search engines increasingly factor user behaviour into rankings, so a site that frustrates visitors tends to rank worse over time.</p>
<h2>What does an audit produce?</h2>
<p>This is where the difference between a free automated tool and a professional audit becomes clear.</p>
<p>A free tool (Lighthouse, SEOptimer, or similar) gives you a score and a list of issues. That is useful as a surface-level check, but it does not tell you which issues actually matter for your business, in what order to fix them, or how much effort each fix requires. You get data; you do not get a plan.</p>
<p>A professional audit produces a scored, prioritised report. Each issue is assessed for severity and business impact. The output is not a list of everything wrong; it is a ranked action plan that tells you what to fix first, why that item matters more than the others, and what the expected outcome is.</p>
<p>Good audits also include explanations in plain language. If you have to hire a separate consultant to interpret the report you just paid for, the audit failed at its job.</p>
<h2>When does a business need an SEO audit?</h2>
<p>There are several situations where an audit provides clear, measurable value.</p>
<p><strong>You have never had one.</strong> If your website has been live for more than six months and nobody has systematically reviewed its SEO, problems are almost certainly accumulating. Websites do not stay healthy on their own. Content management systems update, plugins change, pages get added without proper optimisation, and technical debt builds up silently.</p>
<p><strong>Your traffic has plateaued or declined.</strong> If organic traffic was growing and then levelled off, or if it dropped and you are not sure why, an audit identifies the cause. The fix might be technical, content-related, or competitive; you cannot know until someone looks.</p>
<p><strong>You are about to redesign your website.</strong> A redesign without an SEO audit beforehand is one of the most common ways businesses lose organic traffic overnight. URLs change, redirects get missed, page structure shifts, and rankings disappear. Auditing before the redesign protects what you have already built.</p>
<p><strong>You are investing in SEO but not seeing results.</strong> If you are paying for content, link building, or SEO services and the numbers are not moving, an audit can show whether the investment is going to the right places or whether something foundational is broken underneath it all.</p>
<p><strong>You are entering a more competitive market.</strong> Expanding into a new region, launching a new service line, or going after higher-value keywords all require understanding where you currently stand relative to the competition.</p>
<h2>What an SEO audit does not do</h2>
<p>An audit identifies problems and prioritises solutions. It does not fix anything by itself. A 46-point report sitting in your inbox is useful only if someone acts on it.</p>
<p>This is worth stating plainly because many businesses treat the audit as the destination rather than the starting point. The audit tells you what to do. The next step is implementation; either you handle it in-house, hire someone, or work with the same team that ran the audit.</p>
<p>Some issues flagged in an audit take 30 minutes to fix. Others require a developer, a content writer, or a multi-month effort. Part of the audit's value is distinguishing between these so you know what is realistic given your resources.</p>
<h2>What is the difference between a free tool and a professional audit?</h2>
<p>Free tools are useful for a quick health check. They scan your site automatically and return a standardised report. They are a good starting point if you have never looked at your SEO at all.</p>
<p>However, they have real limitations.</p>
<table>
<thead>
<tr>
<th></th>
<th>Free automated tool</th>
<th>Professional audit</th>
</tr>
</thead>
<tbody><tr>
<td>Scope</td>
<td>Scans visible technical issues</td>
<td>Covers technical, content, keywords, backlinks, competitors, UX</td>
</tr>
<tr>
<td>Prioritisation</td>
<td>Lists issues by type</td>
<td>Ranks issues by business impact and effort</td>
</tr>
<tr>
<td>Context</td>
<td>Generic advice</td>
<td>Recommendations specific to your business, sector, and goals</td>
</tr>
<tr>
<td>Keyword analysis</td>
<td>Limited or absent</td>
<td>Full keyword gap analysis against search intent</td>
</tr>
<tr>
<td>Competitor insight</td>
<td>None</td>
<td>Benchmarked against your actual competitors</td>
</tr>
<tr>
<td>Deliverable</td>
<td>Automated PDF or dashboard</td>
<td>Written report with explanation and action plan</td>
</tr>
</tbody></table>
<p>A free scan might tell you that your page speed is slow. A professional audit tells you that your page speed is slow on your pricing page specifically, that this page gets 40% of your organic traffic, that fixing two oversized images and removing an unused script will solve it, and that this fix should come before anything else because it directly affects conversions.</p>
<p>That difference in specificity is what separates a tool output from a consulting deliverable.</p>
<h2>FAQ</h2>
<h3>How long does an SEO audit take?</h3>
<p>A professional audit typically takes 3 to 8 business days depending on the scope and the size of the site. Basic audits covering core technical and on-page elements are faster. Full audits that include competitor analysis, backlink review, and content gap assessment take longer. Rushing an audit defeats the purpose; thoroughness is the point.</p>
<h3>How much does an SEO audit cost?</h3>
<p>Costs vary widely. Free automated tools exist at one end. Professional audits for SME websites typically range from €250 to €800 depending on scope and specialisation. Enterprise-level audits for large, complex sites can cost several thousand. The key question is not the price but what you receive: a data export or a prioritised plan with clear next steps. <a href="https://illucrum.com/pricing">A full breakdown of audit pricing</a> covers this in detail.</p>
<h3>Can I do an SEO audit myself?</h3>
<p>You can check the basics using free tools like Google Search Console, PageSpeed Insights, and SEOptimer. These will surface obvious technical issues and give you a general sense of your site's health. For a deeper analysis, particularly keyword strategy, competitor benchmarking, and backlink quality, you will need either professional tools (which have their own learning curve and cost) or an experienced auditor. A self-audit is a reasonable first step; it is rarely a complete one.</p>
<h3>How often should a website be audited?</h3>
<p>For most SME websites, a thorough audit once a year is a reasonable baseline. If you are making significant changes to your site (new pages, redesigns, CMS migrations), audit before and after. Sites in competitive or fast-moving sectors may benefit from a lighter quarterly check alongside the annual deep audit.</p>
<h3>What happens after an SEO audit?</h3>
<p>The audit gives you a prioritised action plan. The next step is deciding who implements it. Some businesses handle quick fixes in-house and outsource the more technical or content-heavy work. Others hand the entire plan to the team that ran the audit. Either way, the audit is the starting point of the improvement process, not the end of it.</p>
<h2>Where to start</h2>
<p>An SEO audit gives you clarity. Instead of guessing what might be wrong with your site or which improvements will make the biggest difference, you get a structured answer backed by data. Whether you act on it yourself or bring in help, the audit ensures you are spending time and money on the things that actually move the needle.</p>
<p>If this has raised questions about your own website, <a href="https://illucrum.com/audits/seo-audit/">an audit is a straightforward starting point</a>. And if you already know what needs fixing, the implementation can be handled for you too.</p>
]]></content:encoded></item><item><title><![CDATA[What Is a SaaS SEO Audit?]]></title><description><![CDATA[If you're running a SaaS product and someone suggests an SEO audit, the first question worth asking is: which kind? A standard website audit will catch broken links, slow page speeds, and missing meta]]></description><link>https://blog.illucrum.com/what-is-a-saas-seo-audit</link><guid isPermaLink="true">https://blog.illucrum.com/what-is-a-saas-seo-audit</guid><category><![CDATA[SEO]]></category><category><![CDATA[Seo For Saas,]]></category><category><![CDATA[saas-seo-audit]]></category><category><![CDATA[SEO Strategy]]></category><dc:creator><![CDATA[Szymon Kokot]]></dc:creator><pubDate>Mon, 16 Mar 2026 08:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6938690abe359741ad261496/5b612366-6b60-4e6f-a5ea-b5f3c4e00cf7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you're running a SaaS product and someone suggests an SEO audit, the first question worth asking is: which kind? A standard website audit will catch broken links, slow page speeds, and missing meta tags. Useful, but it won't tell you whether your organic strategy is actually built to acquire users. SaaS businesses don't sell from a brochure. They sell through funnels, free trials, demo pages, comparison content, and review platforms. A generic audit doesn't know to look at any of that.</p>
<p><strong>In short:</strong> A SaaS SEO audit examines not just technical health, but whether your site captures search demand at every stage of the buyer journey, from awareness to signup. It checks what generic audits miss: funnel-stage keyword coverage, JavaScript rendering, comparison page strategy, trial page optimisation, and third-party review platform presence.</p>
<hr />
<h3>What Makes SaaS SEO Different?</h3>
<p>Most business websites exist to inform and convert. A SaaS website does that too, but the conversion path is longer, more competitive, and more distributed. Your potential customer might first read a blog post, then search for a comparison ("your product vs competitor"), then check a review on G2 or Capterra, and only then land on your pricing page.</p>
<p>That means the SEO challenges for a SaaS site are structurally different from those of a local business or a services firm:</p>
<ul>
<li><p><strong>The funnel has distinct stages with different search intent.</strong> Someone searching "what is project management software" is at the top. Someone searching "Asana vs Monday" is in the middle. Someone searching "Asana pricing" is at the bottom. Your site needs content targeting all three and most SaaS sites only cover one or two.</p>
</li>
<li><p><strong>JavaScript rendering is a real concern.</strong> Many SaaS marketing sites are built with React, Next.js, Vue, or similar frameworks. If Google can't render your JavaScript properly, your pages might not be indexed at all, regardless of how good the content is.</p>
</li>
<li><p><strong>Third-party platforms carry significant weight.</strong> Review sites like G2, Capterra, and TrustRadius often outrank your own site for your product's name. Your presence and optimisation on these platforms is part of your organic strategy, whether you've acknowledged it or not.</p>
</li>
<li><p><strong>Trial and demo pages are conversion-critical.</strong> These pages need to rank, load fast, and convert; but they're often afterthoughts from an SEO perspective.</p>
</li>
</ul>
<p>A generic SEO audit doesn't check any of this. It will tell you your page speed and whether your title tags are the right length. It won't tell you that your entire mid-funnel is missing.</p>
<hr />
<h3>What Does a SaaS SEO Audit Actually Check?</h3>
<p>A properly scoped SaaS audit covers the same technical foundation as a standard audit: page speed, Core Web Vitals, crawlability, schema markup, mobile usability; but adds layers that are specific to how SaaS products compete in search.</p>
<p>Here's what the additional coverage looks like:</p>
<p><strong>Funnel-stage keyword coverage.</strong> The audit maps your existing content against the three stages of the SaaS buyer journey. Are you only ranking for branded terms? Do you have any presence in "vs" and comparison searches? Is there awareness-level content pulling in top-of-funnel traffic? Most SaaS sites discover that one or two stages are virtually empty.</p>
<p><strong>JavaScript rendering and indexability.</strong> The audit checks whether Google can actually see your content. This means comparing the raw HTML served to crawlers against the fully rendered page. If key content, headings, body text, internal links, only appears after JavaScript execution, there's a risk that Google is indexing an empty shell. This is one of the most common and most damaging issues on SaaS sites, and it's completely invisible in a standard audit.</p>
<p><strong>Comparison and alternative pages.</strong> When someone searches "[your product] vs [competitor]" or "best [category] software", you want to be the one answering that query, not a third party. The audit assesses whether these pages exist, whether they're structured for search intent, and whether they're actually ranking.</p>
<p><strong>Trial and demo page SEO.</strong> Your signup flow might be the highest-value page on your site. The audit checks whether trial and demo pages have proper meta tags, schema markup, clear CTAs, fast load times, and whether they're even indexed. Surprising numbers of SaaS sites accidentally block their trial page from Google via robots.txt or noindex tags.</p>
<p><strong>Third-party review platform presence.</strong> G2, Capterra, TrustRadius, Product Hunt; the audit checks whether your product is claimed, optimised, and actively managed on the platforms that matter for your category. These listings often rank for your own brand name. Leaving them unoptimised means someone else controls what searchers see first.</p>
<p><strong>Programmatic SEO opportunities.</strong> Many SaaS products have natural data assets, integrations lists, supported tools, use-case categories, industry verticals that could generate dozens or hundreds of indexable pages using a template-based approach. Think of how Zapier has a page for every integration, or how Notion has a page for every use case. The audit assesses whether a similar opportunity exists and whether your tech stack supports it.</p>
<p><strong>Blog and content strategy assessment.</strong> Is the blog active? Does it link to product pages? Is it targeting keywords that actually bring in potential users, or is it a disconnected content island? For SaaS, the blog is often the primary organic acquisition channel and also the most frequently neglected one.</p>
<hr />
<h3>The Funnel Coverage Problem Most SaaS Sites Have</h3>
<p>This is the single most common issue a SaaS SEO audit surfaces, so it's worth explaining in detail.</p>
<p>Most SaaS companies start their content strategy at the bottom of the funnel, branded terms, pricing pages, feature pages. These rank relatively easily because nobody else is competing for your brand name. So from the inside, it looks like SEO is working.</p>
<p>But the middle and top of the funnel are where the real volume lives. The people searching for "best project management tool for remote teams" or "how to manage client projects" are your future customers, they just don't know your product exists yet. If you're not visible for those searches, you're not in the consideration set, and no amount of bottom-funnel optimisation will compensate.</p>
<p>A SaaS audit quantifies this gap. It maps keyword coverage across all three funnel stages and shows you, concretely, where the holes are and what content would fill them. This is where an audit stops being a technical exercise and becomes a growth strategy document.</p>
<p>If you're not sure whether your site has this kind of gap, an SEO audit will flag it, along with every other structural issue worth addressing.</p>
<hr />
<h3>What Should a SaaS SEO Audit Report Include?</h3>
<p>A useful SaaS audit report should give you more than a list of red and green indicators. Here's what to look for:</p>
<ul>
<li><p><strong>A scored assessment for every check</strong>: not just pass/fail, but a calibrated score that tells you how much each issue matters relative to the others.</p>
</li>
<li><p><strong>A prioritised action plan</strong>: ranked by impact, not alphabetical order. The first item on the list should be the thing that will move the needle most.</p>
</li>
<li><p><strong>Funnel coverage analysis</strong>: a clear view of which stages you're winning and which are empty.</p>
</li>
<li><p><strong>Competitor context</strong>: how your organic presence compares to the two or three competitors your prospects are actually evaluating you against.</p>
</li>
<li><p><strong>SaaS-specific recommendations</strong>: not generic advice that could apply to any website, but recommendations that reflect how your product competes in search.</p>
</li>
</ul>
<p>A report that only tells you your page speed score and that you're missing some alt text is not a SaaS SEO audit. It's a generic technical check with a different label.</p>
<hr />
<h3>FAQ</h3>
<p><strong>How is a SaaS SEO audit different from a standard SEO audit?</strong></p>
<p>A standard audit focuses on technical health, on-page elements, and backlinks. A SaaS audit adds funnel-stage keyword analysis, JavaScript rendering checks, comparison page assessment, trial/demo page SEO, review platform presence, and programmatic SEO opportunity scanning. The technical layer is the same, the strategic layer is fundamentally different.</p>
<p><strong>Does every SaaS company need a specialised audit?</strong></p>
<p>If your product competes for search traffic, and most SaaS products do, whether they've invested in it or not, then yes. A generic audit will miss the issues that matter most for how SaaS buyers actually find and evaluate software. The funnel gaps and JS rendering issues alone are worth the specialised scope.</p>
<p><strong>How long does a SaaS SEO audit take?</strong></p>
<p>Typically 5–10 business days depending on the size of the site and the tier. A basic audit covering the core checks is faster. A full audit including competitor analysis, keyword gap mapping, and programmatic SEO assessment takes longer, but produces a strategy document, not just a checklist.</p>
<p><strong>What should I do after receiving the audit?</strong></p>
<p>Start with the top three items on the prioritised action plan. These are chosen for maximum impact with reasonable effort. If you want help implementing the findings, that's the natural next step, but the audit is designed to be actionable whether you implement it yourself or bring in help.</p>
<hr />
<h3>Closing</h3>
<p>A SaaS product deserves an SEO audit that understands how SaaS products actually compete in search, through funnels, comparisons, review platforms, and content, not just page speed and meta tags. If you've been considering an audit, make sure it's scoped for what your product actually needs. And if you already know what needs fixing, the audit is still the fastest way to confirm you're prioritising the right things.</p>
<p>Illucrum's SaaS audit is built around the funnel model above, checking keyword coverage at each stage, JS rendering, review platform presence, and programmatic opportunities alongside the full technical foundation. <a href="https://Illucrum.com/audits/saas-seo-audit">→ See SaaS audit details</a> | <a href="https://illucrum.com/pricing">→ View pricing</a></p>
]]></content:encoded></item><item><title><![CDATA[A "perfect" data structure]]></title><description><![CDATA[Algorythms, data structures and maths. Those are the three legs of the tripod that holds programming. Today, let’s focus on data structures. You know how each one has it strengths and weakneses, each one has it’s own use cases. A “perfect” data struc...]]></description><link>https://blog.illucrum.com/a-perfect-data-structure</link><guid isPermaLink="true">https://blog.illucrum.com/a-perfect-data-structure</guid><category><![CDATA[Programming Blogs]]></category><category><![CDATA[data structures]]></category><category><![CDATA[list]]></category><category><![CDATA[Complexity]]></category><dc:creator><![CDATA[Szymon Kokot]]></dc:creator><pubDate>Thu, 29 Jan 2026 08:00:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769624313917/06cab449-d293-4324-9f58-76b1d7aaef7f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Algorythms, data structures and maths. Those are the three legs of the tripod that holds programming. Today, let’s focus on data structures. You know how each one has it strengths and weakneses, each one has it’s own use cases. A “perfect” data structure should only have strengths and no weakneses, but it should also be useful in all situations. Which is of course ridiculous. There is just no way you can have a data structure that would be able to replace a regular list, just the same as it would be able to replace a tree. Although it’s worth mentioning that a binary tree can be implemented with an array. In this article, I’ll explore the posibilities of coming closer to the “perfect” data structure by trying to design one that would behave like a list while assuring a O(1) complexity for all relevant operations.</p>
<h2 id="heading-algorythmic-complexity">Algorythmic complexity</h2>
<p>Although this article is not about complexity, let’s briefly explain what it is about. The complexity of an algorythm is used to predict how an algorythm will perform depending on the input size. This is very important for data structures that can hold millions of entries. So for example, if we assume a simple node list of which we only have direct access to the first node, if we want to add a new item to it at the beggining, no matter how long the list is, it will always cost the same ammount of resources, which is very good. But if we want to add a new item at the end, we would need to iterate through the whole thing. In this case the time needed to add this new item would be roughly directly proportional to the length of the list.</p>
<p>In some other situations, things are not always that simple. Sometimes the resources needed don’t depend only on the size of the input. Which is very common for sorting algorythms, for example. In those situations, normally the worst case scenario is the most relevant. And this is where the big-o notation comes in, as a way to represent the complexity of an algorythm in it’s worst case scenario. From the previous example of the node list, adding an item at the beggining presents constant complexity, which is O(1). This basically means, it always needs the same amount of resources, no matter how long the list is. Adding an element at the end, presents linear complexity, which is O(n), where n represents the lenght of the list.</p>
<h2 id="heading-the-perfect-list">The “perfect” list</h2>
<h3 id="heading-goals">Goals</h3>
<p>First, let’s define the goals that the list I’m trying to describe should meet. The goal is to have a data structure on which we can perform these operations with O(1) complexity:</p>
<ul>
<li><p>Retrieving any element given it’s index</p>
</li>
<li><p>Adding a new element on any position</p>
</li>
<li><p>Removing any element</p>
</li>
</ul>
<p>As we can retrieve any element given it’s index, there should be of course no problem with iterating the list. So this goals should really cover it all.</p>
<h3 id="heading-restrictions">Restrictions</h3>
<p>This list will have one very important restriction. It will have a set maximum size. This is sadly necessary, I don’t see the possibility of avoiding this restriction.</p>
<h3 id="heading-structure">Structure</h3>
<p>It’s clear to me, that in a way, what I’m trying to achieve is to create something like an “indexed hash table”. This seems to be the most promising approach. To start with, let’s set the maximum size to 4 elements. This should give as a list big enough to see more clearly how it works, but also small enough to make it quite simple to simulate. The list will have the following components:</p>
<ul>
<li><p>The buckets: there should be as many buckets as many elements the list can hold at the same time. In our case it will have 4 bucket. Each will have it’s own identification binary number assigned to it, so we will have buckets 00, 01, 10 and 11. The buckets will really behave like wrappers of the elements stored in the list, and they themselves will be stored in a hash map, using their identifiers as keys. This will assure that we can access any element given it’s bucket number with constant complexity.</p>
</li>
<li><p>A size variable: there should be a variable to keep track of the current size of the list. Nothing special about it.</p>
</li>
<li><p>The state number: the buckets hold the elements, but it’s important to have a way of keeping track of how the buckets are odered. As our list can hold at most 4 buckets, and each has a 2 bits long key, an 8 bit long number will be used , which will contain the four buckets identifiers concatenated, in the order in which the buckets are ordered. Let’s consider the least significant two digits represent the first bucket, the two most significant digits represent the last bucket on the list.</p>
</li>
</ul>
<p>The size variable, is there mostly to make sure the inputs are valid. Most of the magic will happen with the state number, as by manipulating it the order of the buckets will be read and written.</p>
<p>So for example, let’s say we start with a list like this:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>State number</td><td>Size</td><td>Elements ordered from left to right</td></tr>
</thead>
<tbody>
<tr>
<td>00 01 10 11</td><td>3</td><td>1 - 2 - 4</td></tr>
</tbody>
</table>
</div><p>This would mean we would have a list with three elements, bucket 11 holding value “1“, bucket 10 holding value “2“ and bucket 01 holding the value “3“, while the bucket 00 remains empty. So now let’s say we want to add a “3“ between the “2” and the “4”. We would put the value “3” into the empty bucket 00, and place it between the buckets 01 and 10. This would give us:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>State number</td><td>Size</td><td>Elements ordered from left to right</td></tr>
</thead>
<tbody>
<tr>
<td>01 00 10 11</td><td>4</td><td>1 - 2 - 3 - 4</td></tr>
</tbody>
</table>
</div><p>Now, every bucket has a value attached to it. If we wanted to remove the first value (index 0), we would empty the bucket 11, and move it to the “end”. So our list should look like this:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>State number</td><td>Size</td><td>Elements ordered from left to right</td></tr>
</thead>
<tbody>
<tr>
<td>11 10 00 10</td><td>3</td><td>2 - 3 - 4</td></tr>
</tbody>
</table>
</div><h3 id="heading-retrieving-any-element-given-its-index">Retrieving any element given it’s index</h3>
<p>This is fairly simple. It’s sufficient to first check if the given index is allowed. Obviously you can never get the third element from a list with only two elements in it. For that we have the size variable. Once the given input is checked, we need to check which bucket is located at the indicated index. We can do that using the following formula:</p>
<p>$$b = {s \bmod 2^{2*(i+1)} \over 2^{2*i}}$$</p><p>Where <em>b</em> is the bucket number, we of course ignore any decimals; <em>s</em> is the state number and <em>i</em> is the index.</p>
<p>This way, no matter how long the the list is, we can retrieve any element by “just“ calculating the proper bucket. So it presents O(1) complexity.</p>
<h3 id="heading-adding-a-new-element-anywhere">Adding a new element anywhere</h3>
<p>First things first, we of course need to validate the input. After that we should get the last bucket, which will be always empty if the list is not full. This can be done using the previous formula and giving the index the value of 3. Once we have the bucket we can set it’s value. The we need then to modify the state number accordingly. To do so, we can use the following formula:</p>
<p>$$s\prime=s mod 2^{2i} + b * 2^{2i} + {{s/2^{2i}} * 2^{2(i+1)}}$$</p><p>Where <em>s’</em> is the new state number, we only care about the binary eight least significant digits; <em>s</em> is the old state number, <em>i</em> is the index and <em>b</em> is the bucket we are using.</p>
<p>And of course we need to update the index.</p>
<p>This time it’s not as simple as before, as we have to perform two calculations, not just one. But still the algorythm is independent from the lenght of the list, giving it the desired complexity.</p>
<h3 id="heading-removing-any-element">Removing any element</h3>
<p>By now it should be more or less clear how this will look like. First we need the make sure that the index we are given is valid. Then, we will retrieve the bucket for that index in the same fashion that we did before, so we can empty it. And then we can use the following formula to put the bucket at the “end”:</p>
<p>$$s\prime=(s-smod2^{2*(i+1)}/2^2)+(smod2^{2i})+b2^6$$</p><p>Where <em>s’</em> is the new state number, <em>s</em> is the old state number, <em>i</em> is the index and <em>b</em> is the bucket.</p>
<p>And last but not least, we of course need to update the index.</p>
<p>And also in this case, it’s enough to perform two calculations to remove any element with complexity O(1).</p>
<h2 id="heading-final-thoughts">Final thoughts</h2>
<p>This list idea, surely could be optimized. For example, as the number of states is finite, no calculations are really needed. It would be enough to map the whole thing, basically making a finit state machine. Nevertheless, this solution has a big drawback. And that is the maximum length.</p>
<p>Nowadays, we are using 64 bit processors. The biggest list could have at most 16 elements, each with a 4 bit id, which gives as a state number of 64 bits long. This would allow us to perform the calculations easily. Surely it’s possible to do maths with numbers longer than 64 bits on 64 bit processors, but something tells me that this wouldn’t really work fast enough. But maybe I’m mistaken.</p>
<p>On the other hand, designing finite state machines should always work quite well, but that would be very memory heavy. And of course it would also take a lot of time to design and then implement. But maybe it is worth a try?</p>
]]></content:encoded></item><item><title><![CDATA[Class loading and linking in Java]]></title><description><![CDATA[As Java is an object oriented language, the topic of what classes actually are and how are they loaded by the JVM, is one that really goes to the heart of things. In this article, we will explore in more detail not only what is visible to every Java ...]]></description><link>https://blog.illucrum.com/class-loading-and-linking-in-java</link><guid isPermaLink="true">https://blog.illucrum.com/class-loading-and-linking-in-java</guid><category><![CDATA[Java]]></category><category><![CDATA[classloader]]></category><category><![CDATA[jvm]]></category><dc:creator><![CDATA[Szymon Kokot]]></dc:creator><pubDate>Tue, 16 Dec 2025 08:00:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765623238231/c274ff4a-ce0a-41f3-9e25-55692b356463.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As Java is an object oriented language, the topic of what classes actually are and how are they loaded by the JVM, is one that really goes to the heart of things. In this article, we will explore in more detail not only what is visible to every Java developer, but also what is hidden under the hood of the JVM.</p>
<h2 id="heading-class-loaders">Class loaders</h2>
<p>Let’s keep it relatively simple for a while, and let’s start with something more “tangible“ for a regular developer like tha class loaders. Class loaders, most often are Java classes extending <code>java.lang.ClassLoader</code>, which are responsible for loading other classes. To be more precise, they load the bytecode of a class, then they leave it to the JVM to do the linking, basically reading and analyzing the bytecode to create a new class.</p>
<h3 id="heading-hierarchy"><strong>Hierarchy</strong></h3>
<p>By default, a Java application has three main class loaders:</p>
<ol>
<li><p><strong>Bootstrap loader:</strong> The first class loader to run, it is used to get the absolute basic system loaded - essentially <code>java.base</code>. It is not a Java class, it’s written in native code and it doesn’t perform any checks on the classes it loads, so for security reasons it doesn’t have a representation in Java (as a class or class instance, for exmaple), and for this reason it’s refered as <code>null</code>.</p>
</li>
<li><p><strong>System loader:</strong> When the bootstrap loader is done loading the core of the system, the systen loader loads the platform modules that the application depends on. This class loader is a Java, as we said earlier, extending <code>java.lang.ClassLoader</code>. Not only it’s accessible through a static function (<code>ClassLoader.getSystemClassLoader()</code>), it can also be set when starting the application. So if you want to run your app with a custom system class loader, you just need to add to your command the <code>-Djava.system.class.loader=my.custom.ClassLoader</code> flag.</p>
</li>
<li><p><strong>Application loader:</strong> The last loader to run, is the most widely used. It’s basically the one that loads the application itself. It is also an instance of a Java class, just like the system class loader.</p>
</li>
</ol>
<h3 id="heading-delegation">Delegation</h3>
<p>Generally speaking, a class in Java can’t be loaded twice by the same class loader, but it can be loaded multiple times by different class loaders. This is one reason why there is a hierarchy of class loaders. And the second reason, is delegation, which purpose is precisely to avoid the same class to be loaded twice. A properly implemented class loader always delegates that task to it’s parent (the class immediately above in the hierarchy) before attempting to load it by itself. So, let’s say we want the application class loader to load the class A.</p>
<ol>
<li><p>The application loader delegates the task to the system class loader.</p>
</li>
<li><p>The system loader delegates the task to the bootstrap class loader.</p>
</li>
<li><p>The boostrap class loader has no parent, so it tries to load A and if it is able to do so, it returns it to the system loader.</p>
</li>
<li><p>When the system loader receives A from its parent, it just passes it through to the application loader. If not, it tries to load A by itself and return it to the application loader.</p>
</li>
<li><p>If the application loader receives class A from the system loader, there is nothing more to do. If it doesn’t, then the application loader is the last one to give it a try.</p>
</li>
</ol>
<p>Of course, you may add your own, totally custom class loaders. And those, although it would be a good thing if they followed delegation placing themselves beneath the app loader, in some cases they are implemented to break that rule on purpose.</p>
<h3 id="heading-initiating-and-defining-loaders">Initiating and defining loaders</h3>
<p>A class loader is said to be the defining loader of a class A, if A was actually loaded by that class loader. So if the app loader was the one that started the loading process, but due to delegation it was the bootstrap loader that actually found and loaded A, then the bootstrap loader is the defining loader of A.</p>
<p>A class loader is said to be the initiating loader a class A, if the class loader is either the one that started the process that loaded A or is also the defining loader of A. This means a class A can have two initiating class loadeds. In the previous example, the initiating class loaders would be both the app loader and the bootstrap loader.</p>
<p>This is quite important, we will talk about it later on.</p>
<h2 id="heading-jvm">JVM</h2>
<p>Now that we know what class loaders do, let’s focus on what the JVM does. This is where the fun really begins. This part is maybe a little bit more abstract as I will try to explain the concepts without getting into the details of specific implementations. The JVM is the responsible for making sure everything is secure and optimized so there is no errors and no unnecessary calls to the class loaders.</p>
<h3 id="heading-linking">Linking</h3>
<p>When a class loader finds the bytecode of the class to be loaded, the JVM takes over and starts creating it’s own representation of the class. This is refered to as linking and it is done in four steps:</p>
<ol>
<li><p><strong>Verification:</strong> First, the JVM needs to make sure that the bytecode loaded is a valid representation of a class and that it’s code is well behaved.</p>
</li>
<li><p><strong>Preparation:</strong> Once the bytecode is verified, the JVM starts allocating and getting the static variables of the class making them ready to initialize.</p>
</li>
<li><p><strong>Resolution:</strong> Now, before initializing the class, the JVM tries to resolve the supertype and implemented interfaces if any of the class being linked. If the JVM is not able to resolve them, it first tries to load and link them before continuing.</p>
</li>
<li><p><strong>Initialization:</strong> In this step, it’s the first time the bytecode of the class is actually being executed. In this step, all static fields are initialized as well as any static initialization blocks are run. When this is done, the class is ready to be instantiated.</p>
</li>
</ol>
<h3 id="heading-klasses">Klasses</h3>
<p>The representation of a class used by the JVM is the “klass” and it is not a Java class, they are stored in the metaspace. Each klass is unique, and all instaces of the class it represents, are created based on of that klass. Some of the information it contains is accessible from Java through the <code>java.lang.Class</code>, which instances are Java representations of different classes. This is what makes reflection possible, but that is a topic for a different article.</p>
<p>In the metaspace, klasses are not just stored in any way, they are organized. Each class loader has a dictionary assigned to it. Each klass is stored in the dictionary of it’s initiating loader. And it’s also important to point out, that each klass contains information about it’s defining loader.</p>
<h3 id="heading-loading-and-linking-process">Loading and linking process</h3>
<p>Let’s consider a class A, which has been defined by the app class loader. And let’s also consider a class B that is being referenced from A.</p>
<ol>
<li><p>When B is referenced while executing A, the JVM finds out from A’s klass which is it’s defining class loader, in our example it’s the app loader.</p>
</li>
<li><p>The JVM now check in the app loader’s dictionary if contains B. Which we could also express as, the JVM checks if the class loader already is an initiating loader for B. If it is, the JVM grabs the B klass and continues executing A.</p>
</li>
<li><p>But if the app loader is not an initiating loader of B, the JVM asks the app loader to load B.</p>
</li>
<li><p>Now all delegation steps explained before follow.</p>
</li>
<li><p>When B get’s loaded, it’s klass representation gets stored inside it’s initiating class loaders dictionaries for future reference.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Klasses are the representation of Java classes in the JVM. They are not only identified by their name, but also by their defining class loader. This is the reason why a class can be loaded multipple times by different class loader and get treated as completely different classes. Which is the reason why delegation and class loaders hierarchy is needed. Klasses are stored in the metaspace in a dictionary assigned to it’s initiating loaders, which helps the JVM to improve performance in not having to call the class loader each time some class gets referenced.</p>
]]></content:encoded></item><item><title><![CDATA[Java Hot Code Reloader]]></title><description><![CDATA[Without a doubt, Java is a wonderful language. It's fast, strongly typed, has C-like syntax, basically everything I like in a programming language. And also it has some other useful features like being safe or platform independent. But it has one dra...]]></description><link>https://blog.illucrum.com/java-hot-code-reloader</link><guid isPermaLink="true">https://blog.illucrum.com/java-hot-code-reloader</guid><category><![CDATA[Java]]></category><category><![CDATA[classloader]]></category><category><![CDATA[jvm]]></category><category><![CDATA[bytecode]]></category><dc:creator><![CDATA[Szymon Kokot]]></dc:creator><pubDate>Thu, 11 Dec 2025 08:00:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765311279922/018304a2-fb72-49fe-93b2-b905fa6e9960.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Without a doubt, Java is a wonderful language. It's fast, strongly typed, has C-like syntax, basically everything I like in a programming language. And also it has some other useful features like being safe or platform independent. But it has one drawback. And it is that every small change in code needs a application restart to take effect. This can be quite frustrating.</p>
<p>Of course, it isn't true for all projects, because this issue can be solved using different tools. But all of them have one thing in common, they use some kind of trick. The aim of this article is to explore the problem of hot code reloading in Java, and explain some possible solutions, including the one I used in my own project: the <a target="_blank" href="https://github.com/Illucrum-LLC/JHCR/releases"><strong>Java Hot Code Reloader</strong></a>.</p>
<hr />
<h2 id="heading-class-loading"><strong>Class loading</strong></h2>
<p>How are classes normally loaded by the JVM? This is quite simple, class loaders are used. The class loaders in the JVM are a separate very interesting subject, worth of exploring on its own. Here we will only rapidly go through the basics we need.</p>
<h3 id="heading-can-classes-get-loaded-twice"><strong>Can classes get loaded twice?</strong></h3>
<p>First, it's good to know that each class, can't be loaded twice by the same class loader, but it can be loaded twice by two different class loaders. Loaded classes are not identified internally only by their names, but also by the class loader that defined them.</p>
<h3 id="heading-class-loader-hierarchy"><strong>Class loader hierarchy</strong></h3>
<p>In a normal Java application, there are three class loaders:</p>
<ol>
<li><p><strong>Bootstrap loader:</strong> first class loader; represented by <code>null</code>, it is not accessible in any way from Java. It is used to get the absolute basic system loaded - essentially <code>java.base</code>.</p>
</li>
<li><p><strong>System loader:</strong> second class loader in the hierarchy, it can be accessed calling <code>ClassLoader.getSystemClassLoader()</code>. This loader loads the rest of the platform modules that the application depends upon. We can set a custom system class loader by running the java application with the <code>-Djava.system.class.loader=com.custom.CustomClassLoader</code> flag.</p>
</li>
<li><p><strong>Application loader:</strong> the last class loader in the standard hierarchy, it's the most widely used in the application.</p>
</li>
</ol>
<h3 id="heading-loading-a-class"><strong>Loading a class</strong></h3>
<p>When a class is to be loaded the loadClass method of a class loader is called. A correctly implemented loadClass method follow these steps:</p>
<ol>
<li><p>Calls findLoadedClass method. In the end, it's a native method, that searches if the target class has been loaded before. If it wasn't, we continue.</p>
</li>
<li><p>It calls the loadClass method of it's parent (the class loader immediately above in the hierarchy), to avoid loading the same class twice from different class loaders.</p>
</li>
<li><p>If the parent was unable to load the target class, the class loader calls its own findClass method, which attempts to find the target class. If it fails, the loader throws a ClassNotFoundException.</p>
</li>
</ol>
<h3 id="heading-how-the-loadclass-method-is-called"><strong>How the loadClass method is called?</strong></h3>
<p>The loadClass method can be called in two ways:</p>
<ol>
<li><p>It can be called manually, explicitely.</p>
</li>
<li><p>It can be called automatically by the JVM. But there's a catch. Remember the findLoadedClass method? Each class loader has it's own "cache", where all classes loaded by that class loader are saved. To save time. The JVM only calls the loadClass method only if it is unable to find the class in the class loaders cache.</p>
</li>
</ol>
<hr />
<h2 id="heading-instrumentation"><strong>Instrumentation</strong></h2>
<p>So, where is the problem? Well, the problem is that Java doesn't really allow overriding classes, unloading them so they can be loaded again, or loading the same class twice. An attentive reader may now say something like <em>"wait, didn't you say a class can be loaded twice by differnet class loaders?"</em>. And to you, dear reader, I answer: yes. Absolutely yes. I will explain this matter later on, in the "Some possible solutions" section.</p>
<p>Even though you can't reload classes, there is something Java gives you: Instrumentation. An what does Instrumentation give us?</p>
<h3 id="heading-redefinition"><strong>Redefinition</strong></h3>
<p>Instrumentation gives us redefinition. You can redefine classes, although there are limitations. The class structure needs to remain the same. No new methods, no removing methods, no renaming methods, non of the same to fields. It's a nice tool, but quite limited in a development environment.</p>
<h3 id="heading-transformers"><strong>Transformers</strong></h3>
<p>Transformers can be very useful too. They allow you to intercept the bytecode of a class before it is loaded or redefined. Having the bytecode, the content of a compiled class, you have full control over the class that is being loaded. You can change it's behavior, add custom methods, or even create a completely new class from scratch.</p>
<hr />
<h2 id="heading-some-possible-solutions"><strong>Some possible solutions</strong></h2>
<p>So it's quite clear now, that Java offers a very well designed environment, that works very well with a normal setup. But it doesn't really allow reloading classes. It allows redefinition, but that is not enough. So, what tricks can be used to solve this?</p>
<h3 id="heading-custom-jvm"><strong>Custom JVM</strong></h3>
<p>First let's mention the obvious one. Which basically is, you don't like how Java works? Just create you own version tailored specially for you! Easy, right? You don't have to create a whole new language from scratch, just replace a small part of its environment, one of the parts that makes Java so safe. After all, if it is to be used only in development, not in production, that's a perfectly valid solution. And it is used for example by <a target="_blank" href="https://dcevm.github.io/"><strong>DCEVM</strong></a>.</p>
<h3 id="heading-replacing-away-class-loaders"><strong>Replacing away class loaders</strong></h3>
<p>As promised, the complete answer to the attentive reader. Yes, you can load the same class (or different versions of the same class) by two differnt class loaders with no problems. But that would mean getting rid off your original class loader, and creating a new one which would have to load all classes all over again. After all, if you have a class A, that references another class B, you modify B and load it with another class loader, class A keeps referencing the class B loaded by the first class loader. So you have to load A again too, so it references the new version of B.</p>
<p>It is still a solution and it is actually used by some tools, like <a target="_blank" href="https://docs.spring.io/spring-boot/reference/using/devtools.html"><strong>Spring Boot DevTools</strong></a>.</p>
<h3 id="heading-jhcrs-solution"><strong>JHCRs solution</strong></h3>
<p>And what solution did I find? JHCR uses a double approach. At first, it tries using redefinition. When that is not possible, things get a little more interesting. First, lets see what elements are involved:</p>
<ol>
<li><p>Custom class loader</p>
</li>
<li><p>Custom cache memory to save already loaded classes</p>
</li>
<li><p>A transformer</p>
</li>
</ol>
<p>Now, lets say there is a Class A:</p>
<ol>
<li><p>Before loading any class, a transformer intercepts its bytecode, modifying it in a way, each call to a constructor of any class, explicitely calls the loadClass method of the custom class loader.</p>
</li>
<li><p>A hasn't been loaded before, so the loadClass method of my custom class loaders gets called normally.</p>
</li>
<li><p>It finds the class and saves it in a custom cache of the class loader (although there is no way of not saving the class in the default cache).</p>
</li>
<li><p>When the A class gets modified, a file watcher gets its new bytecode and changes the name of the new class version to A1.</p>
</li>
<li><p>Then the custom cache gets modified, so next time the loadClass method gets called for A, A1 is returned instead.</p>
</li>
<li><p>Because each constructor call has been modified forcing an explicit call to the loadClass method of our custom class loader, the default cache is never really used and from now on A1 is returned and instanced where needed instead of A.</p>
</li>
</ol>
<p>Of course, this way, changes to A do not apply for already existing instances of A, but it works like a charm for any new instances. And that is how the second version of the JHCR works.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Hot code reloading is not a trivial issue in Java. But it can be done using different tricks, and everyone comes with its own problems. This is what makes the this matter so interesting and complex. All the things that were briefly mentioned here, are definitely worth of investigating on their own: class loaders and delagation, the Instrumentation API, JVM internals, bytecode manipulation. And there are things that were not mentioned for the sake of simplicity, like reflection, which also plays an important part in making JHCR work.</p>
]]></content:encoded></item></channel></rss>