
Introducing Seeded Randomisation into an SSR Gatsby Project

One of the more recent topics of discussion with my airline client has been around the equal prioritisation of content, and how we can avoid an excessively long and large page whilst still giving items of content equal billing on their homepage.
In this instance, we're talking specifically about the different destinations that the airline flies to. Attempting to find a way to display information for more than a dozen locations at once without overloading the user or resulting in a chaotic mess of content is difficult. This is made doubly so when, in reality, the content creators actually want to display more than thirty or forty locations at once.
The interim solution, for now, has been a carousel (even though I'm not at all a fan of carousels), which allows the content creators free reign to include or exclude as many items as they wish, safe in the knowledge that they are all there and accessible for everyone:
An Argument for Randomisation
There is an alternative, though, and it's something I have been a bit of a fan and advocate of for a very long time: randomisation.
In the dynamic world of web development, randomised content serves as a way to present different items to your users fairly and equally. I spent much too much time finding ways to introduce randomisation into one of the previous versions of my portfolio simply to add a level of novelty to what was otherwise a fairly mundane grid. What it did mean ‑ however ‑ is that a visitor would be just as likely to be presented with the work I did for the London 2012 Olympics in that key top‑left corner as they were to see my work with the Christian festival Rock Nations in that top spot. I even strongly believe that randomisation helps with SEO, offering signals back to search engines that the content is fresh and changes regularly.
This is something that I carry on across my personal (and client) projects even now; the order of the projects that flicker past your eye as you first load my homepage is random, as are the Featured Projects a few scrolls downwards.
By finding ways to introduce randomness into your website, you add an element of interest that keeps the experience fresh and engaging, encouraging and driving user exploration deeper into the site whilst ensuring a balanced exposure of all content.
The Challenge: Randomisation in SSR
This is all well and good, but when it comes to developing an application or website that relies on Server‑Side Rendering (SSR), randomisation poses a significant problem and a unique set of challenges. At their core, traditional client‑side randomisation methods such as Math.random() simply are not compatible with an SSR environment.
When an SSR site is built (as is the case with Gatsby), the server pre‑renders pages into static HTML which ensures quick load times, ideal for a good user experience (and for SEO). However, if these pages contain elements that are randomised using methods like Math.random(), then the version that the server generates will be different across each render, and different again to the version that the client‑side JavaScript then attempts to rehydrate the page with.
This leads to hydration errors and a phenomenon known as a "mismatch".

The Importance of Consistent Rendering
This mismatch between server‑rendered and client‑rendered content can be more than just a cosmetic issue; it can lead to a jarring user experience as elements appear to change abruptly on the page during client‑side rendering. At worst, this leads to the entire page being painted by the browser for a second time as part of the hydration process. At best, this is inelegant.
As SSR becomes a more routinely accepted and expected way of developing dynamic websites, there is also evidence that suggests that this inconsistency can be confusing for users and may lead to a negative impact on SEO.
The Challenge
So, the challenge is to introduce randomisation into a website but in a way that is consistent and predictable across both the server and client sides. The goal is to have the server and the client render the same randomised content for each user visit, each time.
Really, the challenge is to find a predictable, consistent, and non‑random way of making things look random...
As you might appreciate, this is the exact opposite of the very definition of 'random', but it can still result in something extremely similar.
The Solution: Seed‑Based Pseudorandomness
Embracing Determinism
The key to reconciling randomisation with the deterministic nature of Server‑Side Rendering lies in a concept known as seed‑based randomisation (and I use the term 'randomisation' loosely from here on out).
Traditional random number generators produce completely unpredictable results (although even Math.random() isn't truly random), whereas using a seed‑based approach means we can generate random numbers that are predictable and repeatable when provided with the same initial 'seed'.
The Power of Using Dates as Seeds
The issue when it comes to SSR versus client‑side is finding a stable seed, which is where using the date comes in...
By using the current date (or a format of it) as the seed, we can ensure that the randomisation process yields the same results across both server and client renders on a given day (or month, or hour).
As an example, formatting the current date as YYYYMMDD provides a daily‑changing seed, so although your content may remain in the same 'random' order for the day (arguably, this is preferable from a usability perspective anyway), anybody revisiting your application the next or another day will be presented with an all‑new ordering and hopefully some fresh content that they did not see the day before.
Using this approach, where we align the 'randomish' outputs from both the server‑side and client‑side, we can start to address the core issue in SSR‑mismatch. Quite simply: that they need to output the same thing...
Practical Applications and Flexibility
The beauty of this solution is its flexibility. Depending on your specific need, the seed can be adjusted to change more frequently (e.g., hourly) or less frequently (e.g., weekly), allowing precise control over how often the randomised content changes.
This makes seed‑based randomisation using dates a powerful tool if you want to add a dynamic yet consistent element to your Gatsby/SSR project.
Step‑By‑Step Implementation
Integrating seed‑based randomisation into a Gatsby project is relatively straightforward and can be accomplished with native JavaScript, allowing you to develop a reusable utility function that can be imported and used across your application.
I should say here that whilst there are also libraries like seedrandom available for more complex needs, most of the time this is simply going to import way more weight to your project than is necessary. A basic implementation can be done without third‑party dependencies.
Creating a Seed‑Based Randomisation Function
1. Generating a Date‑Based Seed:
The first step is creating a function that we can use to generate our seed. Consistency across time zones is important here to make sure that we don't end up in a scenario where the client side is in a different time zone than our server, so we'll use the UTC date as our seed:
const getUtcDateSeed = (): number => { const now = new Date(); const seedString = now.getUTCFullYear().toString() + (now.getUTCMonth() + 1).toString().padStart(2, '0') + now.getUTCDate().toString().padStart(2, '0'); return parseInt(seedString, 10);};Here, we're generating a date‑based number based on the current (UTC) date in the format YYYYMMDD. We can then use this number as a seed for our pseudorandomisation.
2. Implementing a Basic Seed‑Based Random Generator:
Once we have our seed, we need to create a simple random number generator function. Here's a basic implementation:
const seededRandom = (seed: number): (() => number) => { let hash = seed; return () => { hash = (hash * 9301 + 49297) % 233280; const x = Math.sin(hash) * 10000; return x - Math.floor(x); };};Here, we're generating a pseudo‑random number between 0 and 1. When the same seed is used as a starting point, it will always return the same (random) number, making it appear both random but reproducible.
This works by first applying a simple mathematical formula to the seed: (hash = (hash * 9301 + 49297) % 233280).
This formula is designed to efficiently scramble the seed, using the parameters of a linear congruential generator (LCG), and creating a new number that seems unrelated to the previous one. The use of 9301, 49297, and 233280 is somewhat arbitrary ‑ you can change these to any number you want. However, the combination of these numbers in the formula affects how well the algorithm distributes values, which is why you will see most hash implementations of this type using those specific values.
Once the seed has been hashed, our function uses Math.sin() to manipulate the number even more, ensuring that the final output is a fractional between 0 and 1.
3. Using It in Your Project
It may well be that you only ever want to generate random(ish) values based off the date, so having these as two separate functions may be a little irrelevant for your use case. I tend to prefer to keep them separate like this, though, simply because it allows a little more flexibility.
So, to generate a random (but the same for the day) number in your Gatsby project, you would do something a little like this:
const seed = getUtcDateSeed();const randomNumber = seededRandom(seed);Optional: Using Third‑Party Libraries
I touched on this a little further up the page here, but if you have particularly complex randomisation requirements, you might also consider using a third‑party library like seedrandom. These types of libraries can offer more advanced features and better statistical randomness. However, for most use cases, the above method is more than enough.
Advanced Tips
Aligning Cache with Seed Change Frequency
One of the more nuanced aspects of implementing seed‑based randomisation, especially when using dates as seeds, is aligning this approach with your website's caching strategy. Caching can inadvertently lead to inconsistencies if not properly aligned with the seed change frequency.
Daily Seed Change
: If your seed changes daily (using aYYYYMMDDformat for example), you need to ensure that your cache expiration aligns with this cycle. Ideally, the cache should be refreshed or invalidated at the start of each new day (in UTC time, if you're following my example from above) to correspond with the seed change. This prevents a scenario where a user receives a cached page with the previous day's randomised content.Custom Seed Frequencies
: If you're using a custom frequency (e.g., changing the seed every hour or week), adjust your caching strategy accordingly. This ensures that users always receive the most current version of randomised content as per the seed schedule.
This also means that you need to ensure that your server‑side content is rendered at least once a day. I tend to use a repeating cron job to kick off a new build just past midnight every day,
Handling Client‑Side Randomisation Post‑Load
Whilst seed‑based randomisation is excellent for initial page loads, you might also want to introduce randomness in client‑side interactions after the page has loaded. This can be achieved through additional JavaScript that runs in the browser, independent of the server‑side seed.
Event‑Triggered Randomisation
: Implement randomisation on client‑triggered events like clicks, scrolls, or page interactions. Since these events occur post‑load, they won't conflict with the server‑side rendered content. You can use standardMath.random()for these purposes, as the need for SSR consistency does not apply here.Periodic Content Updates
: For dynamic content that updates regularly (like news feeds or social media posts), you can use client‑side JavaScript to fetch and display new content at set intervals. This can also be randomised using client‑side seeds or simplyMath.random(), adding a layer of dynamism to the user experience.User‑Specific Randomisation
: Consider incorporating user‑specific elements (like time of day or user preferences) in your client‑side randomisation logic. This can make the user experience more personalized and engaging.
Wrapping up
Using randomness in your Gatsby (and other SSR'd) projects needn't lead to hydration issues. Using date‑based seed randomisation can offer a unique blend of dynamism and consistency whilst maintaining the integrity of Server‑Side Rendering (SSR).
This approach solves the challenge of displaying randomised content predictably, ensuring that all users experience the same version of the site at any given moment, despite the underlying randomness.
Using a date‑based seed, particularly with adjustments for time zones and cache alignment, ensures that the content remains consistent across various user visits.
As with any web development technique, the real potential of seed‑based randomisation really only comes to the surface through experimentation; my project needs and yours may differ wildly, but with each project presenting unique challenges and opportunities, they also present the opportunity to use randomisation in this way.
Related Articles

LeetCode: Converting Roman Numerals to Integers. JavaScript’s Math.random(). JavaScript's
Math.random()
Controlled vs. Uncontrolled Components in React. Controlled vs. Uncontrolled Components in React

Valid Palindrome in JavaScript: Two Pointers and Normalisation. Valid Palindrome in JavaScript: Two Pointers and Normalisation

Understanding Signals in Angular: The Future of Reactivity. Understanding Signals in Angular: The Future of Reactivity
Automatically Submit Sitemaps to Google During Gatsby Build. Automatically Submit Sitemaps to Google During Gatsby Build

React Hooks: Modern State Management. React Hooks: Modern State Management

Why this Changes in JavaScript Event Handlers and Methods. Why
thisChanges in JavaScript Event Handlers and Methods
For...in vs. for...of in JavaScript. for...invs.for...ofin JavaScript
Default Parameters in JavaScript: A Guide. Default Parameters in JavaScript: A Guide

What is a Static Site Generator? What is a Static Site Generator?

Optimising gatsby‑image Even Further. Optimising
gatsby‑imageEven Further