XB Labs FiveM
A custom storefront for my FiveM scripts, with checkout on Tebex.
- Role
- Design, development and hosting
- Year
- 2026
- Live site
- fivem.xb-labs.uk

- pages prerendered
- 8
- automated browser tests
- 26
- WCAG 2.2 accessibility
- AA
- cookies or trackers
- 0
The brief
I sell FiveM scripts and resources. Tebex already handles the catalogue and checkout, but I wanted a shop that looks like my other sites and keeps buyers on a page I control until they pay.
The store had to work from a public token only: no backend, no Tebex.js, no private key, and nothing stored on the server. Payments stay on checkout.tebex.io. It also had to meet the same bar as everything else I ship: 360px phones, keyboard and screen-reader use, reduced motion, and readable HTML with JavaScript off.
What I built
- A home page, store listing, package page, basket, and the complete and cancel return pages
- Live catalogue and basket calls to the Tebex Headless API, using the public token only
- Sign in with Cfx.re through Tebex’s basket auth, so the licence goes to the buyer’s account
- Friendly errors when Tebex is down or identity verification is still pending
- Privacy, terms and contact pages written for UK law, with no cookies or analytics
Engineering highlights
Real HTML for every page
The same prerendered React Router 7 setup as my other sites, so the shop loads as real HTML and still works if JavaScript is off. The catalogue then hydrates from Tebex in the browser.
Public token only
The Tebex private key never enters the repo, the client bundle or the container. Checkout happens on Tebex’s own pages, so this site never sees card details.
A strict security policy
No inline scripts or styles. The Content Security Policy stays at “default-src 'self'”, with connect-src only for the Headless API and images from Tebex’s CDN.
Accessibility tested on every change
Built to WCAG 2.2 AA. Twenty-six automated browser tests run axe checks on every page, at phone and desktop sizes, before each release.
Private by design
No cookies, no analytics and no server-side storage. The basket id lives in sessionStorage only for that visit, and the privacy notice says so.
Lean, repeatable hosting
A small read-only container behind the same shared Caddy proxy as my other sites, deployed with one script that runs every check and keeps the previous release for rollback.
Built with
- React 18
- React Router 7
- TypeScript
- Vite
- SCSS modules
- Vitest
- Playwright
- axe-core
- Docker
- Caddy
- Tebex Headless API


