A browser bundles two separate engines: one renders HTML/CSS, the other runs JavaScript. See how Blink+V8, Gecko+SpiderMonkey, and WebKit+JSCore pair up.
"Browser engine" is one of the most casually misused terms in web development, because a browser doesn't actually have one engine — it has two, doing completely different jobs. A rendering engine turns HTML and CSS into the pixels on your screen. A JavaScript engine executes the scripts that make the page interactive. They run side by side, they're built by the same vendor, and people constantly talk about them as if they were interchangeable. They aren't, and the distinction matters for more than trivia: JavaScript-engine quirks are their own identity signal, separate from whatever the rendering engine reveals.
Key Takeaways
- A browser pairs a rendering (layout) engine, which parses HTML/CSS and paints pixels, with a separate JavaScript engine, which executes scripts — they are two different pieces of software.
- The three real pairs: Blink + V8 (Chrome, Edge, and other Chromium browsers), Gecko + SpiderMonkey (Firefox), and WebKit + JavaScriptCore (Safari and, under Apple's rules, effectively every browser on iOS).
- A page load runs both halves together: the rendering engine's parse → style → layout → paint pipeline proceeds alongside the JavaScript engine executing scripts that can modify that same pipeline mid-flight.
- JavaScript engines have their own detectable fingerprint — floating-point rounding, error-message wording,
TypedArraybehavior, JIT warm-up timing — independent of which rendering engine sits next to them. - BrowserInsight's kernel check inspects both halves, because a spoofed browser has to fake the rendering engine's behavior and the JavaScript engine's behavior to be convincing.
Two Engines, One Browser
Open any browser and, under the hood, two separate pieces of software cooperate to show you a page. The rendering engine (sometimes called the layout engine) reads the page's HTML and CSS and figures out what to draw. The JavaScript engine reads and runs the page's <script> code — arithmetic, DOM manipulation, event handlers, everything dynamic.
They are genuinely separate codebases with separate jobs, built and versioned independently even inside the same browser project. A rendering engine has no idea how to execute JavaScript; a JavaScript engine has no idea how to lay out a <div>. What connects them is a binding layer that lets JavaScript call into the DOM the rendering engine maintains — which is also why "the JavaScript engine changed the page" and "the rendering engine drew the page" are two separate events, not one.
Our browser engines guide covers Blink, Gecko, and WebKit as rendering engines in depth. This post is about the half that guide only mentions in passing: the JavaScript engine sitting right next to each of them.
The Three Real Pairs
Despite dozens of browser names on the market, there are only three rendering engines and three JavaScript engines in meaningful use, and each vendor pairs its own:
| Browser(s) | Rendering engine | JavaScript engine |
|---|---|---|
| Chrome, Edge, Opera, Brave, and other Chromium browsers | Blink | V8 |
| Firefox | Gecko | SpiderMonkey |
| Safari, and effectively every browser on iOS/iPadOS | WebKit | JavaScriptCore (also called Nitro) |
Blink + V8. Google maintains both. V8 compiles JavaScript to machine code through multiple tiers of just-in-time (JIT) compilation, trading compile time for execution speed as it learns which functions run hot. Blink hands V8 the <script> content and exposes DOM objects V8's runtime can call into.
Gecko + SpiderMonkey. Mozilla's pair, developed in tandem since the Netscape era. SpiderMonkey's "Warp" JIT overhaul, shipped in Firefox 83, restructured its tiering to cut memory use and speed up real-world pages — a good example of a JavaScript engine evolving independently of any rendering-engine change happening at the same time.
WebKit + JavaScriptCore. Apple's pair, and the one iOS browsers are stuck with. JavaScriptCore escalates through four tiers — the LLInt interpreter, then the Baseline, DFG, and FTL JIT compilers — each trading more compile time for more execution speed as a function proves itself worth optimizing. All four run off one shared bytecode format, which WebKit reworked in 2019 to cut its memory cost roughly in half.
Because Apple requires iOS browsers to use WebKit, "Chrome for iPhone" is running Blink's UI conventions on top of WebKit and JavaScriptCore — not V8. It only feels like Chrome. Underneath, both engines are Apple's. The EU's Digital Markets Act has begun to crack that requirement since iOS 17.4, but in practice iOS browsers are still WebKit — inside the EU and out.
Watching Both Engines Work on One Page Load
A single page load makes the split concrete. When your browser fetches a page, roughly this happens:
- Parse — the rendering engine reads the raw HTML and builds a DOM tree; it reads the CSS and builds a style tree.
- Script execution begins — as soon as the engine hits a
<script>tag (or an already-parsed deferred script fires), the JavaScript engine takes over, running code that can read and rewrite the DOM the rendering engine just built. - Style + Layout — the rendering engine combines DOM and CSS into a render tree and computes the position and size of every box, accounting for anything JavaScript changed.
- Paint — the rendering engine turns that layout into actual pixels.
If a script mutates the DOM after the initial paint — appending an element, changing a class, animating a style — steps 3 and 4 run again for just the affected region. This loop, JavaScript engine and rendering engine handing control back and forth, repeats for the life of the page. Neither engine can do the other's job, but a slow one bottlenecks the whole loop: a rendering engine can't paint content a stalled JavaScript engine hasn't finished computing, and a fast JavaScript engine is wasted if the rendering engine can't lay out its output quickly.
Why the Split Matters for Identity and Detection
This isn't just an architecture footnote — it's the reason browser identification has to check two things, not one.
A rendering engine leaves behavioral fingerprints through how it paints: font rendering, CSS feature support, layout rounding. A JavaScript engine leaves an entirely separate set of fingerprints through how it computes: floating-point rounding on edge-case math, the exact wording of built-in error messages (TypeError text differs subtly between V8, SpiderMonkey, and JavaScriptCore), TypedArray and Array method edge-case behavior, and JIT warm-up timing — how many calls it takes before a hot function gets optimized. None of that depends on layout at all.
A concrete one you can check in any console: new Error().stack. V8 leads the string with the error's name and message and formats each frame as at fnName (url:line:column). SpiderMonkey and JavaScriptCore both drop that header and write frames as fnName@url:line:column. Same language, same standard, three different string shapes — decided entirely by which JavaScript engine is executing, and visible to any script that asks.
That independence is exactly what makes JavaScript-engine signals valuable for spoof detection. A script that fakes its user-agent string, or overrides navigator properties to claim a different browser, changes what the page reports — but it doesn't change which JavaScript engine is actually executing the code underneath. If a page claims to be Safari on iOS but its JavaScript engine's error-message wording and floating-point behavior match V8, not JavaScriptCore, that's a real inconsistency a script can measure directly, no rendering involved.
This is why BrowserInsight's kernel check doesn't stop at rendering-engine detection — it probes JavaScript-engine behavior too. A believable spoof has to get both halves of the browser consistent, which is considerably harder than editing one string.
Frequently Asked Questions
Is Blink the same as V8?
No. Blink is Google's rendering engine — it parses HTML/CSS and paints the page. V8 is Google's separate JavaScript engine — it executes scripts. Both live inside Chrome and other Chromium browsers, and Google builds both, but they are distinct codebases with distinct jobs.
Does Firefox use the same JavaScript engine as Chrome?
No. Firefox pairs Gecko (rendering) with SpiderMonkey (JavaScript), which is Mozilla's own engine — unrelated to Google's V8. Chrome, Edge, Brave, and other Chromium browsers all use V8.
What JavaScript engine does Safari use?
JavaScriptCore, also known as Nitro — Apple's own engine, paired with the WebKit rendering engine. Because Apple requires iOS browsers to use WebKit, browsers on an iPhone run JavaScriptCore too, regardless of what browser they claim to be. The EU's Digital Markets Act has allowed alternative engines on iOS since 17.4, but in practice essentially every iOS browser still ships on WebKit and JavaScriptCore.
Can two browsers share a rendering engine but use different JavaScript engines?
Not among today's major browsers — each vendor ships its rendering engine and JavaScript engine as a matched pair (Blink+V8, Gecko+SpiderMonkey, WebKit+JavaScriptCore). It's technically possible to mix and match, since the engines are separate projects, but no mainstream browser does.
Conclusion
A browser engine and a JavaScript engine are not the same thing, even though the same handful of vendors build both and browsers are commonly described by just one name. Blink pairs with V8, Gecko with SpiderMonkey, WebKit with JavaScriptCore — three genuinely independent pairs doing two genuinely independent jobs, cooperating on every single page load. Because the JavaScript engine leaves its own behavioral trail — separate from anything the rendering engine reveals — a real check of "what browser is this" has to look at both. Run BrowserInsight's kernel check to see which pair your browser is actually running.
Recommended Reading:


