How to detect Safari and iOS versions with ease in 2025

Cover for How to detect Safari and iOS versions with ease in 2025

Why is accurately detecting the version of Safari and iOS you’re dealing with so important for modern web development? The reasons are seriously many: applying fixes/enhancements only where needed, preventing confusion for users on other browsers, displaying the right prompts for actions or installations, enabling or disabling features, providing accurate analytics, and support users with tailored instructions, especially since some browsers “masquerade” in their user agent strings or behave differently in WebViews. In this post, we’ll talk about how to identify Safari/iOS versions with ease in 2025 (and beyond).

On iPhone and iPad, Safari’s version is coupled to the OS major version:

  • Safari 26.x ↔ iOS/iPadOS 26.x
  • Safari 18.x ↔ iOS/iPadOS 18.x
  • Safari 17.x ↔ iOS/iPadOS 17.x

…and so on.

In practice, if you can confidently establish the Safari version on iOS (preferably via feature checks tied to WebKit/Safari release notes, rather than raw UA), you also implicitly learn the user’s OS version.

This is valuable because it lets you infer a bit more about the device purely from the web. These insights can guide you on eligibility for system features, security posture, or the instructions to show without native entitlements.

Book a call

Hire Evil Martians

From browser-specific quirks to performance across the board, our team ships polished, scalable products that developers love.

The risks of version misidentification

Before shipping features based on a specific Safari or iOS version, it’s worth considering the risks associated with version misidentification:

  • As one example, when the frontend incorrectly detects the version, it directly degrades UX and, in turn, core metrics.
  • And in many markets, Safari (especially on iPhone and iPad) represents significant traffic share. Thus, even “edge-case” misdetections can impact a noticeable portion of the audience.
  • When users consistently encounter missing features, warnings like “browser not supported,” or degraded behavior in Safari, they are less likely to return, pushing retention down over time.

Let’s look at the primary failure modes and how they hit our metrics:

#1. Disabling features that actually work.

Misreading a modern version of Safari as an older one can hide capabilities the browser already supports (like offline mode or push notifications).

UX impact: users see a stripped-down product that doesn’t meet expectations.

Metric impact: lower conversion and reduced satisfaction.

#2. Enabling features that are unavailable or buggy.

While APIs may technically exist, they can still be incomplete or buggy in certain Safari/iOS releases. So, relying only on feature detection can mislead you into using functionality that breaks under real conditions. Using detection version gating helps prevent users from being exposed to unstable features.

UX impact: visible errors, broken flows.

Metric impact: immediate conversion loss and increased abandonment.

#3. Blocking valid users as “unsupported.”

Products that gate access by version risk locking out up-to-date Safari users when detection fails.

UX impact: hard stops and frustration.

Metric impact: sharp drops in activity and satisfaction, users moved to competitors.

Incorrect browser/version detection creates technical debt but it also suppresses conversion by hiding or breaking critical flows and erodes retention through repeated friction. Handle gating with care (favor capability checks over strict version checks) to protect both user experience and business metrics.

Moving past risk (and something to keep an eye on)

After assessing the risks and realizing that you can’t do without functionality tied to a specific version, below we will consider how to do this.

At present, there is no completely reliable method for developers to detect the exact browser and version across all devices, since browsers do not provide a consistent API for this purpose.

However, it’s important to keep an eye on one technology and consider adopting it in the future as it becomes more widely supported: the userAgentData API. That said, it is only supported in Chromium-based browsers at the moment.

Moving on, there are two main approaches to browser detection we can talk about right now.

User-Agent detection

User-Agent Detection relies on reading the browser’s User-Agent string to determine the browser and OS version. This method is often unreliable.

Why is that? The User-Agent string is frequently changed by browser vendors for compatibility and privacy reasons, and many browsers pretend to be others.

For example, Safari’s user agent contains two version numbers: a technical number in the Safari/... token and a marketing version in the Version/... token. Unprepared scripts can misinterpret this data.

Moreover, Apple sometimes freezes or stops updating part of this information: starting with macOS 11, Safari stopped updating the system version (the UA always shows 10.15.7), which makes it impossible to detect the new OS via the user agent.

All these quirks lead to the fact that attempts to “calculate” the browser and version from the UA string are often wrong.

MDN notes that while it’s tempting to tailor a site for specific browsers, doing so reliably is very difficult, and it’s a common source of bugs.

For example, websites often assume that if the string contains “Chrome,” then the browser is Chrome, or that Safari lacks capabilities Chrome supports. But UA strings are unreliable: on iOS, all browsers are WebKit-based and may include “Chrome” or “Firefox” in their string, even though they share Safari’s limitations. As a result, sites may disable features that Safari actually supports, or try to use APIs that the browser underneath cannot provide.

Notably, Apple recommends using the “feature detection” approach instead of relying on User-Agent.

However, in some cases, such as identifying specific iOS versions or handling edge cases, User-Agent checks are necessary and cannot be fully replaced.

Feature detection

Feature Detection is usually the preferred approach. It directly checks whether a browser supports specific APIs or CSS features.

This method is more robust and future-proof, but it cannot always distinguish between all iOS or Safari versions, since many features are shared across several releases.

For best results, it’s often a good idea to combine both methods: using feature detection for functionality, and User-Agent detection as a fallback for version-specific cases.

Up next, let’s look at some essential detection tips.

Tip #1: Detection Webkit engine is a good starting point for your research

WebKit is an open-source browser engine created by Apple, used in several browsers, and not just with Safari.

On iOS, browsers like Chrome, Firefox, and Edge are all required by Apple to use WebKit, so WebKit detection will match many browsers besides Safari.

On desktop, while Safari is the main WebKit browser, custom or niche browsers can also use this engine.

While WebKit detection tells you that a browser uses the WebKit engine, it doesn’t tell if it is actually Safari. But we can reliably identify the mobile or desktop WebKit, which will make it much easier to detect the iOS version:

//  Desktop Safari, all mobile WebKit browsers on iOS and webview iOS
function isWebkit() { return "GestureEvent" in window; }

//  all mobile webkit browsers and webview iOS
function isMobileWebKit() { return "ongesturechange" in window; }

//  Desktop Safari
​​function isDesktopWebKit() {
  return (
    typeof window !== 'undefined' &&
    'safari' in window &&
    'pushNotification' in window.safari
  );
}

You can’t definitively define Safari with feature detection alone, but this is the first reliable step to significantly reduce the number of target devices. This approach also allows you make to make further assumptions (for example, about iOS versions) by detecting features introduced in specific iOS releases.

Tip #2: How to detect specific iOS versions

Step 1: Find out which feature was introduced in the iOS version you care about

Go to Apple’s Safari Release Notes or WebKit’s site and look up the iOS/Safari version you’re targeting, then note a feature (API, property, CSS rule) that was added in that version.

For example, say we need to detect all devices from iOS 17.0.
Safari 17.0 on iOS 17 added support for the contain-intrinsic-size CSS property, which lets you provide a fallback size when using size containment.

Step 2: Write a feature detection test for that feature

// Use `CSS.supports` in Javascript or `@supports` in CSS to check if the feature is available.
// true on iOS 17.0+ (Safari 17.0+)
const isAtLeastiOS17 = CSS.supports("contain-intrinsic-size", "100px");

Step 3: Use the test in your code

Run your detection logic and branch your business logic accordingly:

if(isMobileWebKit()){
  if (isAtLeastiOS17) {
    // Safe to use iOS 17+ features
  } else {
    // Fallback for older iOS versions
  }
}

Step 4: Detect only one specific minor version (Optional)

Sometimes a bug only hits the original 17.0 release—while all later 17.x maintenance releases are clean. To zero in on exactly 17.0, pair the “minimum” test above with the absence of a feature first exposed in a subsequent point-release.

You need go to to Apple’s Safari Release Notes or the WebKit Feature Status page again and look up the iOS/Safari the next version you’re targeting

WebKit for Safari 17.0 brought Managed Media Source to iPad and Mac, but only it was only first enabled in the iOS 17.1 beta on iPhone. You can detect the presence of this feature using the global ManagedMediaSource constructor WebKit:

const supportsManagedMediaSource =
  'ManagedMediaSource' in window;

// Combine to isolate 17.0
function isOnlyiOS170() {
  return isAtLeastiOS17 && !supportsManagedMediaSource;
}

if(isMobileWebKit()){
  if (isOnlyiOS170()) {
    // Running iOS 17.0 exactly
  }
}

This way, whenever Apple ships a new web-feature in a particular iOS/Safari release, you can instantly tie it to a minimum OS version without the need User-Agent sniffing.

Step 5: Double version checking

Check all possible versions of iOS, because Safari Release notes and WebKit sometimes fail to include all changes.

For example, you can discover iOS 17.7 notes listed in About iOS 17 Updates, even though Apple never published release notes for Safari. It appears to be a security or maintenance update with no documented web platform changes. This means you can’t detect or exclude only iOS version 17.7.

Tip #3: Always test your code on devices and use visual behavior tests in case of problems

When you try to detect specific iOS versions, it’s crucial to always test your solution on real devices or simulators whenever possible.

Even when you follow release notes and use feature detection, browsers can behave in unexpected ways, leading to edge cases that are only revealed through hands-on testing.

Let’s say we want to target devices from Safari 17.6.
For iOS 17.6, Apple mentioned in the release notes that they added support for a new CSS feature—the safe keyword. This seemed promising: if a browser supports the safe value, it must be running iOS 17.6 or newer!

…right?

However, real-world testing revealed a problem. While Safari “pretends” to support the safe keyword (@supports marks the property as valid), the browser doesn’t actually apply it.

This behavior makes it impossible to reliably detect iOS 17.6 just by checking @supports. Even worse, this was the only new CSS feature documented for that release.

Other changes also weren’t suitable for feature detection. As a result, we could only reliably distinguish up to iOS 17.4; for 17.5 and above, detection became unreliable.

Since @supports proved to be unreliable, we could change tactics and check the actual visual behavior. For example, with the safe keyword, the clipping of text inside a container should differ if it’s genuinely supported.

Using JavaScript’s getBoundingClientRect, we measured the rendered output to see if the safe property was truly applied. To make this concrete, let’s check out from my demo.

The left side shows the layout without safe (or with unsupported safe), where text overflows/clips in the default direction; this is evidence that the browser isn’t honoring the safety constraint.

The right shows a flex container aligned with safe enabled, where overflowing content respects the “safe” edge and clips on the opposite side.

Note the positioning of the text as the size of the box narrows:

Code example:

const isSafeKeywordSupported = () => {
  // Create a detached container and child
  const container = document.createElement("div");
  const child = document.createElement("span");


  child.textContent = "Evil Martians";

  // Apply minimal styles to test `safe`
  container.style.display = "flex";
  container.style.justifyContent = "safe center"; // Test `safe`
  container.style.width = "5%"; // Small width to force potential overflow
  container.style.position = "absolute";
  container.style.top = "-9999px";
  container.style.left = "-9999px";


  // Append the child to the container
  container.appendChild(child);
  document.body.appendChild(container);


  // Check if content is cropped on the left
  const containerRect = container.getBoundingClientRect();
  const childRect = child.getBoundingClientRect();
  const isCroppedOnLeft = childRect.left < containerRect.left;


  document.body.removeChild(container);
  return !isCroppedOnLeft;
};

For reliability, to minimize errors you can first exclude devices up to 17.5 and starting from 18.0 and then use our custom check between 17.5 and 17.7.

Full example here:

const isTargetVersion = () => {

  if(!isMobileWebKit()) return false;

  // Check iOS before 17.5 version
  if (window.CSS && !CSS.supports("text-wrap-style", "stable")) {
    return false;
  }


  // Check iOS 18.0 and later versions
  if (window.CSS && CSS.supports("content-visibility", "visible")) {
    return true;
  }


  // Need to exclude iOS 17.5 version
  return isSafeKeywordSupported()
};

Browsers, especially on iOS, sometimes claim to support features they don’t fully implement, or they change behavior without documentation.

No matter how good your detection logic seems, always test your solution in the wild!

Testing on real devices and across as many versions as possible is the only way to uncover hidden issues and edge cases.

Tip #4: Use User-Agent as an additional source of truth

Everyone knows that relying solely on the User-Agent string isn’t the most dependable approach. However, when combined thoughtfully with feature detection methods, it can become incredibly useful for accurately identifying specific devices or operating system versions.

Imagine you need to detect not just any iOS version, but specifically iPadOS. Using feature detection alone doesn’t allow us to clearly distinguish an iPad from other devices.

Interestingly, Safari on iPadOS 13 sends a User-Agent string identical to that of desktop Safari on macOS by default.

This behavior might initially seem misleading, but in reality, it’s precisely what we need. If the User-Agent matches macOS Safari, yet feature detection indicates a mobile WebKit environment, you can confidently identify the device as an iPad!

Determining the exact version of iPadOS can then be achieved by following the guidelines we’ve previously outlined.

Conclusion detected

Accurately detecting Safari and specific iOS versions is critical for modern web development, especially given the unique limitations and features of genuine Safari on iOS.

However, despite the relative ease of the techniques mentioned here, there is no single, perfectly reliable detection. This is due to Apple’s policies, browser engine similarities, and the evolving, sometimes misleading, nature of browser feature support and User-Agent strings.

Nevertheless, we have a toolkit to help us get the job done as much as possible, and that’s what you have now, too!

TLDR; key takeaways:

  • WebKit detection is not Safari detection: All iOS browsers use WebKit, so you must go further than just checking for the engine.
  • Combine detection strategies: Rely primarily on feature detection (checking for specific APIs or CSS features) to determine browser capabilities, but supplement with User-Agent checks as a fallback for edge cases.
  • Use Safari and iOS release notes. These help you associate features or bugs with particular versions, but beware that not all changes are documented, and release notes may miss minor updates.
  • Cross-check features: To target a specific iOS version, combine detection of multiple features introduced in different versions.
  • Beware of false positives: Sometimes, browsers claim to support a feature but do not actually implement it correctly—requiring behavioral checks, not just presence checks.
  • Test on real devices: The only way to guarantee accurate detection and correct user experience is to validate your logic on actual devices and iOS versions, since simulators and documentation can miss quirks and edge cases.
Book a call

Irina Nazarova CEO at Evil Martians

From browser-specific quirks to performance across the board, our team ships polished, scalable products that developers love.