Safari Extension Error: “Non-persistent background content cannot listen to webRequest events.” after macOS 15.4 / Safari 18.4 Update
We’re seeing the following error in the Safari Extensions tab after updating to macOS 15.4 and Safari 18.4:
“Non-persistent background content cannot listen to webRequest events.”
This error did not appear prior to the update, and we haven’t found any official documentation stating that webRequest API is no longer supported in Safari.
In our extension (Manifest V3), we are using the webRequest.onHeadersReceived callback to intercept response headers and read updated cookies.
While the functionality itself still works as expected. we’re able to access the response headers and this error is now shown in the Extension settings page.
We are not seeing this issue in other browsers (Chrome, Firefox) using the same Manifest V3 setup.
Is there any plan to deprecate webRequest support in Manifest V3 for Safari?
We’d appreciate any clarification or guidance on how to handle this going forward.
Safari Extensions
RSS for tagEnhance and customize the web browsing experience on Mac, iPhone, and iPad with Safari Extensions
Posts under Safari Extensions tag
113 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I'm building a macOS Google Chrome extension.
I need to be able to send messages from the Chrome extension to the macOS app
What's the set up flow?
I've heard about native messaging, but I struggle to implement it.
I've heard about XPC, but not sure JS can send messages to a macOS XPC service.
We’re encountering an issue when trying to add non-standard headers to outgoing requests using Declarative Net Request (DNR) rules in our Safari Web Extension.
Tested on macOS 15.4 with Safari 18.4.
Specifically, when attempting to add a custom header such as "X-Custom-Header" using a DNR rule, the header does not appear in the request. We are able to add standard headers like "Authorization" and "Cookie" to the request successfully using the same method.
This behavior suggests that Safari may be filtering or blocking non-standard headers when set via DNR rules, unlike other browsers.
In Chrome and Firefox, the same rule adds the "X-Custom-Header" header without any issue.
We are looking for assistance in fixing these issues and having our Safari Extension function the same as it does in Firefox and Chrome.
We’re seeing an issue in our Safari Web Extension where not all cookies from the Set-Cookie response header are accessible. We are using macOS 15.4 and Safari 18.4.
In the webRequest.onHeadersReceived callback, the Set-Cookie header returned by Safari only includes some of the cookies set by the server. If multiple Set-Cookie headers are present, we seem to receive only a partial list, some cookies are missing entirely.
In Chrome and Firefox, the same callback provides all cookies set by the server without issue.
We are looking for assistance in fixing these issues and having our Safari Extension function the same as it does in Firefox and Chrome.
When a DNR rule is set for a specific URL and the request receives a server-side redirect (e.g., 302) to a different URL that does not match the urlFilter, the rule still seems to apply to the redirected request. We are using macOS 15.4 and Safari 18.4.
For example, consider two sequential calls: call1 and call2.
call1 triggers a 302 redirect to call2.
A DNR rule is created to add a "Cookie" header to call1 based on its URL.
Unexpectedly, the same cookie is also added to call2, even though call2's URL does not match the rule's urlFilter.
This results in the Set-Cookie response from call1 being ignored, and call2 receiving the manually set cookie instead—leading to incorrect behavior.
This issue doesn't occur in Chrome or Firefox, where the rule is not applied to the redirected request if the URL no longer matches.
We are looking for assistance in fixing these issues and having our Safari Extension function the same as it does in Firefox and Chrome.
My Mac app and its Safari web extension share an app group, and I want to notify the web extension native process when the app makes a change to the app group NSUserDefaults, but I can't find a good way to do this.
According to the documentation, "You can use key-value observing to register observers for specific keys of interest in order to be notified of all updates, regardless of whether changes are made within or outside the current process." In my testing, however, this doesn't work in the web extension process. I'm using NSUserDefaults addObserver forKeyPath, but observeValueForKeyPath never gets called.
I've also tried NSDistributedNotificationCenter, but the web extension process doesn't receive the notifications sent by the main app.
Are either of these supposed to work? If not, are there any alternatives?
iOS 18.4 introduces the new WKWebExtension API to support extensions in WKWebView. However, for extensions that have migrated to Manifest V3 and use an extension service worker as the background script, it's currently not possible to inspect them through Safari.
This is only thing I can see, I don't know how to inspect the details of the "background.js"
I'm wondering—has this changed? Is it now possible to inspect extension service workers?
This browser extension is a doc reading enhancer for the Apple Developer website.
It supports i18n translation, hover link previews, and bilingual display.
Currently, it supports four languages: ja-JP, ko-KR, zh-CN, and zh-TW.
It works with Swift/SwiftUI/Foundation modules now, and it's expected to support Swift Test, Swift Charts, UIKit, Swift Playground, and XCode modules by the end of this month.
For more info, check out: https://appledocs.dev.
You can also visit https://appledocs.dev/progress to see translation progress and vote.
Note: It's only works on Chrome、Edge(In review)、Firefox(In review)
Screenshot:
Topic:
Developer Tools & Services
SubTopic:
General
Tags:
Swift Packages
Developer Tools
Safari Extensions
Apple Intelligence
Safari Version 14.0.1 (16610.2.11.51.8)
I am porting a Chrome/Firefox/Edge extension to Safari Web Extension. Mostly, the process was painless, I am, however, seeing quite different behavior in the tab ids generated by Safari compared to Chrome, Firefox, and Edge. My extension has callbacks for each of these browser.webNavigation events:
browser.webNavigation.onBeforeNavigate
browser.webNavigation.onCommitted
browser.webNavigation.onDOMContentLoaded
In each of these I rely on the tab id for various future tab targeting operations. When opening a new tab, the details object passed to each of these callbacks has a non-zero tabId on Chrome, Firefox, and Edge. However, in Safari, the tabId is always zero. To debug, I added one more callback:
browser.webNavigation.onCompleted
At this point Safari finally has a non-zero tabId in the details param. Needless to say this is causing some consternation with achieving the same outcomes as tab tracking on Chrome, Firefox, and Edge. It's like Safari is treating new tabs as "non tabs" until navigation completes. You can even see it when trying to get the tab by tabId=0:
browser.tabs.get(tabId) // tabId=0 here
	.then(tab => {
		// tab is undefined
	});
Seems like this might be a bug. I can't imagine why the behavior is so different from other browsers. Any ideas on how to work around?
I am trying to build and run a Safari Web Extension from Xcode and I have enabled "Allow unsigned extensions" in Safari settings. However, I see the below pop up:
And, if click on the "Quit and Open Safari Extensions Preferences..." button, the project stops running on Xcode and nothing happens.
What can be the issue? The extension works and runs fine if I get it from the Mac App Store and this only happens when running from Xcode. I even tried completely uninstalling the mac app store version and still facing the same issue.
I'm trying to load a Safari Extension onto my physical iPhone 15 running iOS 18.4 but am seeing the following message: "iOS 18.4 is not installed."
When I click the Get button I see that the download has failed with the following error message. I tried updating my laptop to Sequoia and I also deleted and re-installed Xcode but that didn't fix it. Any thoughts?
Download failed.
Domain: DVTDownloadableErrorDomain
Code: 41
User Info: {
DVTErrorCreationDateKey = "2025-04-08 06:00:22 +0000";
}
--
Download failed.
Domain: DVTDownloadableErrorDomain
Code: 41
--
Failed fetching catalog for assetType (com.apple.MobileAsset.iOSSimulatorRuntime), serverParameters ({
RequestedBuild = 22E238;
})
Domain: DVTDownloadsUtilitiesErrorDomain
Code: -1
--
Download failed due to a bad URL. (Catalog download for com.apple.MobileAsset.iOSSimulatorRuntime)
Domain: com.apple.MobileAssetError.Download
Code: 49
User Info: {
checkConfiguration = 1;
}
--
System Information
macOS Version 15.4 (Build 24E248)
Xcode 16.3 (23785) (Build 16E140)
Timestamp: 2025-04-07T23:00:22-07:00
Summary
Recently a number of bugs affecting our Safari extension have been introduced with various Safari 18.X updates. We've submitted feedback for all of these, but most have received no response. We need to raise this to your attention as it has been affecting our developer experience and causing a lot of frustration for our users. It's something that adds a lot of uncertainty for us. These issues affect core web functionalities but seem to be isolated to the Start Page or Extension environments.
For example:
using window.open, no longer works
using window.location.href = ... no longer works
Including a tag in our start page causes infinite reloading to occur.
registering a content script more than once will crash Safari
Details
Unable to open new window as as start page extension in Safari 18
FB15879470
What happens: Calling window.open does nothing. This broke our links to our feedback submission, marketing site & help site.
When: Nov 18, 2024 - Initial launch of Safari 18 on macOS
Status: Open, No response
Unable to open app url scheme with window.location.href in start page extension in iOS 18
FB15879596
What happens: Changing the URL in this way does nothing (well actually it does work about 10% of the time). This broke our navigation to in app payment.
When: Nov 18, 2024 - Initial launch of Safari 18 on iOS
Status: Open, No response
New tab extensions broken
FB16126043
What happens: Having a tag in your causes an infinite loop of reloading the start page. This broke our entire start page extension.
When: Dec 19, 2024 - Safari 18.3 on iOS beta
Status: 10 similar tickets found, marked for future OS update. We did get a response and a fix is identified for a future release
window.open opens “about:blank” when called from Start Page extension.
FB16427985
What happens: calling window.open from the start page opens about blank on iOS 18.3. Similar to the first issue, but slightly different behaviour. This broke our links to our feedback submission, marketing site & help site.
When: Jan 30, 2025 - Safari 18.3
Status: Open, No response
Registering a content script more than once causes Safari to crash in macOS 15.4 beta
FB16831768
What happens: We have an optional content script that we were registering every time it was used. Although somewhat redundant, it was much simpler than checking if one was already registered and tracking if an updated one needed to replace it. This works fine on all other browsers and all prior Safari versions we've released it on. However if a user enables site blocker on the latest version, as soon as they visit any website, our content script registration causes Safari to crash. Essentially preventing users from using Safari until they uninstall our extension.
When: Mar 11, 2025 - Safari 18.4
Status: Open, No response
In Conclusion
Luckily we have been able to isolate and find workarounds for most of these issues so far, but we are not guaranteed to in the future. We are raising this not only to have these issues looked into, but to raise awareness of the rising trend of basic functionality of Safari extensions breaking with Safari updates. We hope that this can influence a shift in your QA & feedback intake practices to ensure these issues are less frequent in the future.
We are happy to raise future issues through your provided channels as they are discovered. But to have our feedback ignored and then have to rely solely on workarounds to prevent disruptions to our users' experience is concerning.
We submitted this feedback to our developer relations contact, and he suggested we submit a TSI to look into these issues. In response to this, we were advised to post this here.
Hi!
I am writing a browser extension that allows you to control the playback of media content on a music service website. Unfortunately Safari does not support tracking changes to the audible property in an event tabs.onUpdated. Is there an alternative to this event? I'm looking for a way to track when the automatic inference engine interrupts playback on a music service website.
That you.
I'm testing web extension to safari on iOS. I've built and added extension application to simulator, but on safari settings shows no extensions.
I'm using Xcode 16.3 beta 2 with Simulator iOS 18.4 (22E5216h), tested on iPhone 16.
https://app.screencast.com/oUq4EMonmfT7u
https://app.screencast.com/MCquvHzmZi8QS
Typically, you can use the @@extension_id special string to reference the absolute path into the bundled resources of an extension, such as an image or a custom font, in a CSS file.
However, this broke with Safari 18.
Consider this section in a popup.css file:
.card-icon {
height: 16px;
width: 20px;
background-image: url(safari-web-extension://__MSG_@@extension_id__/images/card.svg);
background-size: 20px 16px;
}
In Safari 17.4, once loaded in the browser, @@extension_id is replaced with E8BEA491-9B80-45DB-8B20-3E586473BD47, and the background-image reads as so:
background-image: url(safari-web-extension://E8BEA491-9B80-45DB-8B20-3E586473BD47/images/card.svg);
But as of Safari 18, the @@extension_id just collapses to an empty string, and the background-image reads as so:
background-image: url(safari-web-extension:///images/card.svg);
and the svg fails to load with the following error: "Failed to load resource: You do not have permission to access the requested resource."
This is a regression, does to match the behavior of the other major browsers, and should be fixed.
Filed with Feedback ID: FB15104807
I have a basic setup following WWDC 2020 on Safari Web Extensions and another one on XPC. The video even mentions that one can use UserDefaults or XPC to communicate with the host app. Here is my setup.
macOS 15.2, Xcode 16.2
A macOS app (all targets sandboxed, with an app group) with 3 targets:
SwiftUI Hello World
web extension
XPC Service
The web extension itself works and can update UserDefaults, which can then be read by SwiftUI app - everything works by the book.
The app can communicate to the XPC service via NSXPCConnection - again, everything works fine.
The problem is that the web extension does not communicate with XPC, and this is what I need so that I can avoid using UserDefaults for larger and more complex payloads.
Web Ext handler code:
class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
func beginRequest(with context: NSExtensionContext) {
// Unpack the message from Safari Web Extension.
let item = context.inputItems[0] as? NSExtensionItem
let message = item?.userInfo?[SFExtensionMessageKey]
// Update the value in UserDefaults.
let defaults = UserDefaults(suiteName: "com.***.AppName.group")
let messageDictionary = message as? [String: String]
if messageDictionary?["message"] == "Word highlighted" {
var currentValue = defaults?.integer(forKey: "WordHighlightedCount") ?? 0
currentValue += 1
defaults?.set(currentValue, forKey: "WordHighlightedCount")
}
let response = NSExtensionItem()
response.userInfo = [ SFExtensionMessageKey: [ "Response to": message ] ]
os_log(.default, "setting up XPC connection")
let xpcConnection = NSXPCConnection(serviceName: "com.***.AppName.AppName-XPC-Service")
xpcConnection.remoteObjectInterface = NSXPCInterface(with: AppName_XPC_ServiceProtocol.self)
xpcConnection.resume()
let service = xpcConnection.remoteObjectProxyWithErrorHandler { error in
os_log(.default, "Received error: %{public}@", error as CVarArg)
} as? AppName_XPC_ServiceProtocol
service?.performCalculation(firstNumber: 23, secondNumber: 19) { result in
NSLog("Result of calculation XPC is: \(result)")
os_log(.default, "Result of calculation XPC is: \(result)")
context.completeRequest(returningItems: [response], completionHandler: nil)
}
}
}
The error I'm getting:
Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.***.AppName.AppName-XPC-Service was invalidated: failed at lookup with error 3 - No such process."
What am I missing?
I am creating a Safari Web Extension.
There are two calls let say, call1 and call2 which gets executed in sequence by browser, call1 gives a 302 type response and redirects to call2.
When creating DNR rule for adding "Cookie" in the request header of call1, the same cookie gets added to the request header of call2 as well(Same is the case for other headers/custom headers as-well). Because of this the set-cookie present in response header of call1 is not sent in the request header of call2, and returns 400 response.
The same setting is working fine for other browsers chrome & firefox.
Is this a bug or DNR works differently for safari ?
currently "webRequestBlocking" works in safari for manifest v3, is there any development of it getting removed just like it's removed in chrome in mv3.
Since Safari requires a macOS app as a container for Web Extensions, is there a way to establish native messaging directly from SafariWebExtensionHandler using stdin/stdout? Or does Safari enforce a different communication mechanism?
I’d like to keep the same approach as other browsers.
Any guidance on making this work would be appreciated!
I'm trying to use ES6 module imports in a Safari Web Extension, but despite enabling "type": "module" in the manifest, imports are not functioning as expected.
Specifically when working with a project structure that includes multiple directories.
A root directory containing the manifest.json and main entry point scripts
A scripts/ folder housing core functionality modules
A common/ directory for shared utilities, constants, and helper functions
A background.js file in the root that attempts to import from these various directories
When trying to import modules from the scripts/ and common/ directories into my background.js, I'm encountering complete import failures.
How can I correctly implement cross-directory module imports in Safari Web Extensions?
After upgrading to Safari version 18, we encountered an issue with my extension’s background script not being able to access cookies. Previously, in Safari versions 17 and below, the extension worked as expected. Now, when the extension tries to retrieve cookies using browser.cookies.getAll(), it returns an empty list. However, if we open the extension’s developer tools, the cookies are visible and accessible.
It seems that Safari only provides cookie data after the developer tools have been opened. However, after relaunching Safari and launching the extension without opening the developer tools, browser.cookies.getAll() still returns an empty list.
Has anyone else experienced this?
STEPS TO REPRODUCE
Download this minimal app : https://www.icloud.com/iclouddrive/0bajlhnuQaG6T5NsFKXEB0U9Q#test%5Fcookies
Compile test_mv2 extension (in test_cookies.getAll.zip).
Launch test_mv2.app and activate extension.
Click on the extension's button (browserAction).
Open the developer tools.
Observe an empty list of cookies.
Click on the extension's button (browserAction).
Cookies are retrieved as expected.