• Oct 27, 2021

How to Build a Safari App Extension in iOS 15

iOS 15 finally introduced Safari extensions, one year after Apple brought extensions to Safari on the desktop. Of course, they did it in a very gated, Apple-like way, which makes the process to develop a Safari extension much more difficult than it needs to be. Notably however, you still can't make Chrome extensions on iOS (or Android).

A few weeks ago I set out to build a Safari extension for my app, hbd (you can check out the extension now in the latest update). I didn't find any thorough guides for this like I usually do for other development processes, so I decided to make one.

Let's talk about the practical details of building a Safari Extension on iOS.

Before Beginning

There are some important things to know before developing a Safari extension on iOS.

Extensions must have a containing native application. You can't just upload a Safari extension like you can on the Chrome web store, you have to build an iOS app too (even if it's just a shell for your extension), and go through the whole App Store review process to get it published.

Lots of browser APIs are restricted/unavailable . Most of this is due to the fact that iOS has much stricter memory limits than a computer, so they've added requirements like non-persistent background pages. Read the list to make sure you're not planning to use any restricted APIs.

Tabula Rasa

If you want to start from scratch, Xcode has a project template for Safari App Extensions. Create a new project, then select Safari Extension App. I recommend doing this just to see what the structure of the extension looks like, but I couldn't actually use this in my case, since I had an existing Xcode project that I wanted to add a new extension to.

safari extension swift

If you already have an Xcode project, go to File->New->Target , and select Safari Extension (NOT Safari Extension App). Xcode will add a few boilerplate files in a new group:

SafariWebExtensionHandler.swift is the glue between your native app and the JS code. It implements the NSExtensionRequestHandling protocol, which allows it to receive and respond to messages from the JS.

the Resources/ folder contains all of your extension source code. This should be structured like an unpacked browser extension, with manifest.json at the top level.

safari extension swift

The boilerplate JS files are okay if you're making a basic extension, but won't help very much if you're using a build system and framework like React, which I assume most complex extensions do. If so, you can delete all the files inside the Resources/ folder (we'll replace them later).

If you have an existing Chrome extension that you want to convert to Safari, you can run this command-line tool to convert it (I didn't use this since I was starting my extension from scratch).

Using React

I built my extension using React + Typescript. Coming from a background in Swift, I would highly recommend using Typescript over regular Javascript. If you use SwiftUI, I would also recommend using React. React has a lot of similarities to SwiftUI making it easy to pick up, although it's just a poor man's version of SwiftUI 😎. Here is the basic structure of my code:

safari extension swift

If you use this boilerplate, run npm install after you've cloned it to download all the dependencies. Then, running npm run dev will build the extension and output it to the dist/ subdirectory. This dist/ directory is what we want to tell Xcode about.

Xcode - Groups & References

Xcode's file navigator (in the left pane) shows you a sort of pseudo-file structure of your project. I say pseudo- because it doesn't always represent what's actually stored on your hard drive. There are two ways to add new folders to an Xcode project - using groups or folder references.

If you add a group, new files added to that folder in your Finder don't automatically get added to your Xcode project. In Xcode 13, groups are represented with a gray folder icon.

If you add a folder reference, any new files added to that folder will automatically be added to your project. In Xcode 13, folder references are represented with a blue folder icon.

After researching this, I decided that using folder references is better than using groups. For example, if we add a new image to our extension's icons/ folder, we'd like that image to automatically be added to the Xcode project.

Here's how to accomplish this: No matter where you place your extension directory on your computer, you can open its dist/ subfolder and select all of the files, then drag them into the Resources/ folder in Xcode (NOT finder). Once you do this, a popup will appear:

safari extension swift

Make sure you are not selecting Copy items if needed , and that you are selecting Create folder references. If you select copy items, then all of the files from your dist/ folder will be unlinked from your source code. So if you make some changes and rebuild your extension, those changes won't be included in Xcode.

safari extension swift

If you open up the Resources/ folder in finder now, you will see that there are actually no files there. All of the files are actually stored in the dist/ folder in your extension directory, and are only referenced in Xcode and shown in the pseudo-file navigator. You can confirm this by opening the right pane (⌘⌥0) and looking at the file path for your JS files.

Unfortunately, we can't make the top-level Resources/ folder a folder reference in Xcode; it must be a group. This is a special folder name in Xcode and for some reason they won't let you change it to a folder reference. So if you add a new file to the top-level of your extension's dist/ folder (say you decide to add a new content script), you'll have to drag it into Xcode too. This is one change I would like Apple to make for future releases.

The Development Cycle

After you've set up the files, you can now start developing and testing your extension. The first step is to create a new scheme that runs your extension target:

safari extension swift

Every time you run this scheme, it will ask you which app to launch; select Safari. There may be a way to set this automatically, but I haven't figured it out yet. Using this scheme, you can profile your Extension's memory usage and set breakpoints in your SafariWebExtensionHandler class.

SafariWebExtensionHandler.swift is responsible for handling all messages sent from the JS scripts. The app can only listen and respond to messages; it can't initiate messages to the JS on its own. To send messages to your app, you need to add the nativeMessaging permission in the manifest.json, and use this code :

You should send native messages sparingly, as I'll discuss later on. The main reason to use them would be to request necessary data from UserDefaults or a shared keychain.

Hot Reload?

Web developers are used to hot reload, but that won't quite work here. I used npm run watch to rebuild my extension every time I changed a file, but that will only change what is in the dist/ folder (which is referenced in Xcode). It won't push your new changes on the device you're testing. To do that, you need to re-run the project in Xcode. This is a painfully slow experience. As a sort of compromise, you can download the React Preview plugin for VS Code. It works sort of like the canvas in SwiftUI, but the layout doesn't always match up with mobile Safari, so be sure to test on device.

To debug your extension's JS scripts, you'll need to use Safari on your mac. Open Safari, enable the develop menu , then open the develop menu in the menu bar. Select whatever device you're running on, and select the relevant page, which will bring up a web inspector.

safari extension swift

To my knowledge, there's no way to automatically open a web inspector when you open your popup page. I wish this were the case, since I spent a lot of time manually re-opening web inspectors. Also, every time you re-run your Xcode scheme, your breakpoints get cleared, which sucks. The lack of tooling here is what makes developing Safari Extensions a pain.

So you've tested your extension and its ready to go, now you just need to archive your project and upload it to App Store Connect. There's one small step that you might forget, which is to build your extension source for prod instead of dev mode. This dramatically reduces file size (in my case from 3.6 MB to 240 KB). In dev mode, Webpack includes a source map of your original, unbuilt code so you can debug more easily. If you've looked at your popup.js file inside your dist/ folder, it's a giant mess of unreadable code. Building for prod removes these source maps and minifies your code for production.

You can manually run " npm run build " to build for prod before you archive, or you can set up a script to do it automatically. I prefer the latter. Here's how to do it:

Edit your main app's scheme (not the extension scheme). Then, under Archive->Pre-actions , add a new Run Script Action.

safari extension swift

Write your shell script. Make sure that "Provide build settings from" is set to your app target. There are a few things to note about the actual script:

I used the say command because I wasn't sure the script was actually running, so it helped debug.

Pre-actions aren't logged in the build log, so the second line redirects all output from this script to a file called prearchive.log in my main project directory.

Replace the path in line 4 with whatever path your extension is located at.

safari extension swift

Now every time you archive your app, this script will run and automatically build your extension for production.

Other Challenges

iOS takes memory management seriously. As of iOS 15.0, the memory limit for a Safari Extension is 6 MB. This isn't documented anywhere to my knowledge, but you will discover it once your app is randomly terminated, as I did. This limit only refers swift code in your extension target, not JS/html/css. This seems like an incredibly unfair limit, given that running the template app in Xcode uses 3.8 MB (over 50% of the limit), and most of that is just Apple frameworks. According to one Apple employee on the Apple Dev forum , they're increasing the limit to 80 MB in iOS 15.1. If that's true, it's a 13x jump, which makes me think someone totally miscalculated and it somehow wasn't caught during beta. [Only real devices have this limit, simulators don't.]

safari extension swift

Even if the limit is increased to 80 MB, I would try to use the SafariWebExtensionHandler as little as possible and do most of your work in the JS; the browser does not have the same strict memory limits. In my case, I needed to use native messaging to get the user's auth state from the shared keychain. Other than that, I used node modules and JS fetch requests to get all the data I needed.

It's trivial to ignore the safe area in a native app, but what about in Safari? Turns out Safari uses css environment variables to accomplish this. The only problem was that they didn't work for me. I tried a bunch of different things, like setting viewport-fit in a meta tag , but no matter what, the variables all evaluated to 0px. Maybe I was doing something wrong, but this whole approach is such a mess.

Other notes

In the documentation, Apple specifies to use the browser API namespace, but it seems that chrome APIs work just fine. Why?

Final thoughts

Many people say that the browser is a second-class citizen on iOS, and after developing a Safari extension, I understand why. There's a major lack of tooling here compared to native development. Granted, Safari Extensions are only a few months old.

Apple's strategy has generally been to push towards its native App Store, where it has much tighter control and can extract more value. The browser, on the other hand, is the wild west. For a while people thought that PWAs would be the next big thing, since they work cross-platform out of the box and are easier to deploy and maintain. But that never happened, since the UX of a PWA is still significantly worse than a native app. That must be at least somewhat intentional on Apple's part. Maybe they'll find a way to levy a 30% tax on all payments in Safari, too.

Anyway, the market for browser extensions has never been that big. Compared to the market for mobile apps, it's tiny. Browser extensions tend to be more like utilities (e.g. a password manager, ad blocker, theme provider), rather than full-blown applications. They're called "extensions" for a reason - they're meant to incrementally extend or enhance your browsing experience. The one notable winner here is Honey, a browser extension that got acquired for $4 billion (!) in 2019. I think there are a lot fewer opportunities to build standalone businesses around browser extensions, but they can make a great feature to complement your other apps. That's the approach I took with my app, hbd . (If you've made it to this far, please check out the hbd Safari extension!)

Anytime Apple introduces a user-facing framework like this, it's worth paying attention to. That's the beauty of developing for iOS - every year there are 3 or 4 totally new APIs that affect 1B people. I'm not super bullish on Safari extensions since I don't see any big opportunities, but I wouldn't be surprised to see an emergent viral Safari extension soon. So far, popular Safari extensions look a lot like regular chrome extensions, just ported to Safari. What can you do on iOS that you can't on desktop? What's different about how people use Safari on iOS? Whoever cleverly answers those questions will have a big opportunity on their hands.

If you have any comments, corrections, or improvements to my process, reach out to me at [email protected] and I'll be happy to update this post.

Recent Posts

The Curious Design of Skateboard Trucks

The Smartest Website You Haven't Heard of

Will Two Cars Crash at an N-Way Stop Sign?

Advisory boards aren’t only for executives. Join the LogRocket Content Advisory Board today →

LogRocket blog logo

  • Product Management
  • Solve User-Reported Issues
  • Find Issues Faster
  • Optimize Conversion and Adoption
  • Start Monitoring for Free

Swift extensions: An overview with examples

safari extension swift

In this tutorial, we’ll take you through a basic overview of extensions in Swift. We’ll demonstrate how Swift extensions work by building a simple workout tracking app.

Swift Logo Over a Blue Background

We’ll focus on the following:

What are Swift extensions?

Creating an extension in swift, type properties, mutating methods, separating code, extension on swiftui views, adding initializers to existing types.

Extensions, well, extend existing Swift named types — i.e., structs, classes, enums, and protocol — so you can add more functionality to them. This enables you to insert your own code into existing system code to which you wouldn’t otherwise have access, such as the Foundation framework . You can also use extensions to extend your own code and for code cleanliness.

Creating extensions is similar to creating named types in Swift. When creating an extension, you add the word extension before the name.

You can extend a particular named type, add a new computed instance, and type properties to it. For example, you can extend Color to add your own colors to it. Let’s say our app has a brand color that we want to use everywhere. We could create a constant type property, brand , by extending Color via extension .

Our app also uses custom colors for the row’s background in the settings screen. For this, we’ll define a variable type property that adjusts the color according to the system-wise appearance.

Here’s how you use it:

As mentioned in the introduction, you can extend types to add your own functionality even though you don’t have access to the original codebase. If you want to add a function to Double , for example, you can write an extension on the struct without having access to the original code of Double struct.

In our app, we’re fetching calories data from HealthKit, but the function returns the data in Double type. We want to show the data rounded to one decimal place. We can write an extension on Double like this:

Let’s use this mutating method to solve our problem:

When conforming our classes to protocols, we usually add all the protocol methods in the same class. For example, we would add all the methods of UICollectionViewDataSource , UICollectionViewDelegate , and UICollectionViewDelegateFlowLayout .

We can separate the methods required for each using extensions. This makes the code more readable and more maintainable.

Our app uses Google Sign-In as the main authentication source, so we need to conform to GIDSignInDelegate to receive updates on successful sign-in. We can separate the code required for this — you guessed it — using extensions.

Now let’s say we want to add a custom large title text like Apple uses for the header in most of its apps. This text will denote the date of a particular workout. We want to use the exact custom text for the settings screen as well.

To reuse this piece of code everywhere in the codebase, we will extend Text by adding a largeTitle(:) method.

Now we can use this method on our views:

Similarly, let’s say we want to create a heart button to favorite a set of workouts. We’ll create a ViewModifier that toggles the color of the heart on double-tap:

Now let’s create an extension on View so we can use it in our views:

Finally, we’ll add it as a modifier to the Image :

We can use an extension to add a new custom initializer that accepts different parameters to existing types.

Let’s assume that your designer gives you the colors in hex instead of the RGB value. Using the previous examples of adding a computed type property to Color , we’ll create an initializer that takes a hex value. We can add another initializer if we want to make a color with the RGB value as integers:

We can now use it as:

Extensions in Swift are a powerful way to add your own functionality to types that you do not own. This overview of extensions and the examples herein are designed to help you understand how extensions work so you can implement and use them in your own Swift projects.

Over 200k developers use LogRocket to create better digital experiences

safari extension swift

For further advanced reading, I recommend the following articles from the Swift docs:

  • “ Adding Protocol Conformance with an Extension ”
  • “ Extensions with a Generic Where Clause ”

Get set up with LogRocket's modern error tracking in minutes:

  • Visit https://logrocket.com/signup/ to get an app ID

Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, not server-side

Share this:

  • Click to share on Twitter (Opens in new window)
  • Click to share on Reddit (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to share on Facebook (Opens in new window)

safari extension swift

Stop guessing about your digital experience with LogRocket

Recent posts:.

Integrating Django Templates With React For Dynamic Webpages

Integrating Django templates with React for dynamic webpages

Create a dynamic demo blog site using Django and React to demonstrate Django’s server-side functionalities and React’s interactive UI.

safari extension swift

Using aoi.js to build a bot on Discord

Explore how the aoi.js library makes it easy to create Discord bots with useful functionalities for frontend applications.

safari extension swift

Web Components adoption guide: Overview, examples, and alternatives

Evaluate Web Components, a set of standards that allow you to create custom HTML tags for more reusable, manageable code.

safari extension swift

Using AWS Lambda and CloudFront to optimize image handling

Leverage services like AWS Lambda, CloudFront, and S3 to handle images more effectively, optimizing performance and providing a better UX.

safari extension swift

Leave a Reply Cancel reply

DEV Community

DEV Community

Bing Qiao

Posted on Jan 19, 2022

Creating a browser extension for Safari and Chrome

Projects diagram

Safari extension requires a Swift project that contains iOS/macOS parent apps plus their extension apps that share a bunch of JavaScript and other resources.

The extension from my first attempt here was a crude implementation in plain, vanilla JavaScript. There was no bundling, minifying, framework or typing. There wasn't even a separate JavaScript project. All JavaScript&resources belonged to the Swift project and were managed by Xcode.

After some more research and learning, I recreated the same extension using React/TypeScript, not just for Safari but Chrome too. The new project uses esbuild to create bundled and minified code.

The extension project for Safari and Chrome

A much stripped down version of the extension resources project is hosted here browser-ext-react-esbuild while the container app for iOS/macOS is hosted here browser-ext

The first issue I had to address was how to create a Web extension using React/TypeScript/esbuild. Luckily there is already a template project that does exactly just that. esbuild-react-chrome-extension

The next issue is how to code in TypeScript against Web extension API for both Safari and Chrome. As it turns out Safari and Mozilla Firefox are very similar in their API but there are enough differences between them and Chrome to require different treatment especially when it comes to the use of "callbacks" and "promises" Building a cross-browser extension

Initially I created wrapper functions to convert Chrome functions that require callback to return promise instead. The better approach, as I found out later, is probably to use webextension-polyfill from Mozilla and its types .

A caveat here is, I had to set module in "tsconfig.json" to "commonjs" as shown below:

Then do import assignment in JavaScript files that call extension API:

Using import like below didn't work for me:

The code generated by esbuild for the import above calls __toESM for require_browser_polyfill() which renders the polypill proxy ineffective.

The container Swift project for Safari

Another issue is how to manage the React/extension project with the container Swift project.

The boilerplate extension resources (JavaScript/css, manifest and html files) created with a new Safari extension project are managed by Xcode. But I need them to be simply copied over from the React project, instead of having Xcode creating reference for every JavaScript/html/css/image file that needs to be part of the bundle it creates.

How extension resources get added to Swift app bundle by default

The problem is, we might have different files from the React project depending on whether it's a prod or dev build, especially if the bundler (such as Parcel) used generates randomised file names.

Create a new empty folder

Finally, add the folder to Copy Bundle Resources build phase. This needs to be done for both iOS and macOS extension targets.

Now, all it takes to import new extension resources from the React project is to copy everything over to Resources/build folder in the Swift project.

The two sample projects are setup to work together as long as they are checked out side-by-side in the same directory.

Now you can develop and test the extension against Chrome solely in the extension resources project. To test against Safari, just run an npm command to build extension resources and copy contents of dist to the container Swift project, then build/run it in Xcode.

The mechanism

auto-refresh

Auto-refresh is implemented using setTimeout() , browser.tabs.reload() and browser.storage.local .

  • Every managed (marked to auto-refresh) browser tab has an entry in a map persisted in extension storage local: tabId: boolean ;
  • Upon loading, content.js looks up its tabId in this map;
  • If there is an entry and the result is true , content.js will set up a timer of fixed interval (obviously the interval can be exposed to users too) to send a runtime message to background.js , asking for reload;
  • background.js receives the request and reloads the sender tab via browser.tabs.reload() .

The approach above is different from my first attempt on auto-refresh extension:

  • I was using a variable in background.js to hold tabs states which proves problematic. In Safari iOS, property persistent for background.js in manifest.json needs to be false , which means it can and will get reloaded. That explains why the extension was losing tab states whenever iPhone screen went dark. Using browser.storage.local seems to be the only viable alternative to tackling this issue, even though it adds quite a bit of complexity to the code base.
  • Using browser.storage.local , I now have to figure out a way to clean up tabs states once the browser is restarted. This is a bit tricky for Safari which does not implement extension session API. The approach I used is to do a clean up in browser.runtime.onStartup event. This seems to work well but I'm not certain how water-tight this is.
  • I was using window.location = window.location.href to do the reload. The better way is to call extension API browser.tabs.reload() which allows bypassCache argument to bypass browser cache.

Being able to test Safari extension easily in Chrome during development has saved me a lot of time. I'd be interested to hear if you have different approaches to some issues raised here.

Top comments (0)

pic

Templates let you quickly answer FAQs or store snippets for re-use.

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink .

Hide child comments as well

For further actions, you may consider blocking this person and/or reporting abuse

abdurrahman720 profile image

Add swipe-able button in React

Abdur Rahman - Feb 29

sebastienlorber profile image

This Week In React #179: useActionState, Redwood, React-Navigation, RN-Screens, CodePush, VisionOS...

Sebastien Lorber - Mar 29

serifcolakel profile image

Shared Tailwind Setup For Micro Frontend Application with Nx Workspace

Serif COLAKEL - Mar 29

fpaghar profile image

React Component Design Patterns - Part 2

Fatemeh Paghar - Mar 26

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Search code, repositories, users, issues, pull requests...

Provide feedback.

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly.

To see all available qualifiers, see our documentation .

safari-extension

Here are 75 public repositories matching this topic..., quoid / userscripts.

An open-source userscript manager for Safari

  • Updated Apr 14, 2024

dgraham / Ka-Block

A Safari extension that blocks an artisanal selection of advertising domains.

  • Updated Mar 24, 2023

uetchy / Polyglot

🌏 The missing Safari extension that translates selected text into your native language.

  • Updated May 17, 2023

Swift-open-source / UltraTabSaver

The open source Tab Manager Extension for Safari.

  • Updated Sep 12, 2020

ashchan / safarikai

Safari extension for translating Japanese words.

  • Updated May 23, 2022

brunolemos / simplified-twitter

Remove distractions from the new Twitter layout. Extension for Chrome, Firefox, Safari, Edge & More

  • Updated Nov 22, 2023

lil-org / tiny-wallet

crypto wallet for  safari

  • Updated Apr 16, 2024

AlexPerathoner / Sessions

Safari extension to save your working sessions

  • Updated Sep 28, 2023

dwarvesf / session-buddy

An ultra-light Safari extension helps you save open tabs as collections that can be easily restored later

  • Updated Sep 28, 2020

ethanhuang13 / blahker

巴拉剋 - Safari 蓋版廣告消除器

  • Updated Oct 5, 2022

bermudalocket / Tweaks-for-Reddit

A Safari App Extension to help make Reddit suck just a little less on Safari 13+. Written (mostly) in SwiftUI.

  • Updated Jun 19, 2022

filimo / ReaderTranslator

PDF/WebPages Reader with embedded Google Translate and voice engine on SwiftUI, Combine, Catalyst, AppKit

  • Updated Dec 27, 2023

kyle-n / WebExtensionTemplate

Create a browser extension for Chrome, Firefox and Safari in no time.

  • Updated Jul 10, 2023

shumbo / Svadilfari

Gesture Control for Safari on iOS and iPadOS

  • Updated Mar 30, 2024

soffes / ZoomIn

Safari extension for opening Zoom right away

  • Updated Nov 10, 2020

natclark / safari-wallet

Ethereum browser extension wallet for Safari on macOS & iOS.

  • Updated Nov 5, 2021

git-shawn / QR-Pop

A clean, convenient, and privacy-first QR code generator for macOS, iOS, and watchOS built with SwiftUI.

  • Updated Dec 4, 2023

jasperswallen / uBlock-Origin-Safari

Remake uBlock Origin as Safari App Extension

  • Updated Jul 23, 2020

MoralAlberto / Send-It-for-Slack

Add Slack functionality with this Safari Extension

  • Updated Oct 17, 2017

JosephDuffy / Overamped

Safari Web Extension to disable AMP ⚡️

  • Updated Jan 7, 2023

Improve this page

Add a description, image, and links to the safari-extension topic page so that developers can more easily learn about it.

Curate this topic

Add this topic to your repo

To associate your repository with the safari-extension topic, visit your repo's landing page and select "manage topics."

SwiftLee

A weekly blog about Swift, iOS and Xcode Tips and Tricks

Every Tuesday, curated Swift content from the community for free.

Give your simulator superpowers

RocketSim: An Essential Developer Tool as recommended by Apple

SwiftLee > Swift > Extensions in Swift: How and when to use them

In this article

Extensions in Swift: How and when to use them

What is an extension, extending types without having access to the source code.

Extensions in Swift allow you to extend types, even when you don't have source code access.

Using extensions to create default protocol implementations

Conforming to a protocol using an extension.

Stay updated with the latest in Swift

The 2nd largest newsletter in the Apple development community with 18,327 developers .

Featured SwiftLee Jobs

  • Lead Software Engineer @ M7 Health • $105K - $185K
  • Senior Android Engineer @ Speechify
  • Test Automation Lead, Engineering Productivity @ Ordergroove • $140K - $170K

Find your next Swift career step at world-class companies with impressive apps by joining the SwiftLee Talent Collective. I'll match engineers in my collective with exciting app development companies. SwiftLee Jobs

Use Safari extensions on your Mac

Safari extensions enhance and customize the browsing experience on your Mac. Here's how to install them, uninstall them, or share them across devices.

Safari extensions add functionality to Safari, so you can explore the web the way you want. Extensions can show helpful information about a webpage, display news headlines, help you use your favorite services, change the appearance of webpages, and much more. Extensions are a great way to personalize your browsing experience.

Install extensions

Turn on extensions, turn off extensions, uninstall extensions, share extensions across devices.

Use the App Store to conveniently download and install Safari extensions. All extensions in the App Store are reviewed, signed, and hosted by Apple for your security, and they're automatically kept up to date.

Start by installing the latest macOS updates to make sure that Safari is up to date. You need Safari 12 or later to get Safari extensions from the App Store.

Open Safari and choose Safari > Safari Extensions from the menu bar.

The App Store opens to the Safari Extensions page. To download and install an extension, click Get or click the price. You might be asked to sign in with your Apple ID.

Click Install.

After the extension is installed, click Open and follow the onscreen instructions provided by the extension.

After installing an extension, follow these steps to turn it on.

Choose Safari > Settings (or Preferences).

Click Extensions.

Select the checkbox next to the extension's name. Learn what to do if you can't turn on extensions .

If you're browsing privately, or using a profile or web app

When browsing in a private window in macOS Sonoma or later, all extensions that require website access are turned off by default. To use an extension when browsing privately:

Choose Safari > Settings.

Select the extension in the sidebar, then select “Allow in Private Browsing” on the right.

Whether or not you're browsing privately, you can also restrict the extension's access to certain websites. Click the Edit Websites button to view the extension in Websites settings. From there you can allow access, deny access, or require that websites ask you for access.

When using Safari profiles , extensions for the default profile are managed in the main Extensions tab of Safari settings. Extensions for other profiles are managed in the Profiles tab, which has its own Extensions tab for each profile. By default, extensions are turned off for each new profile.

Share button

Choose Safari > Settings (or Preferences), then click Extensions.

To turn off an extension, deselect its checkbox.

If you can't determine what an extension does, or you don't expect to use it again, you should uninstall it.

To uninstall an extension, select the extension and click the Uninstall button.

Starting with macOS Ventura, iOS 16, and iPadOS 16, you can share extensions across your Mac, iPhone, and iPad:

On your Mac, open Safari and choose Safari > Settings, then click Extensions. Select “Share across devices” at the bottom of the window.

On your iPhone or iPad, go to Settings > Safari > Extensions, then turn on Share Across Devices.

No alt supplied for Image

To uninstall an extension from all devices, you must uninstall it on each device.

Safari no longer supports most web plug-ins. To load webpages more quickly, save energy, and strengthen security, Safari is optimized for content that uses the HTML5 web standard, which doesn't require a plug-in. To enhance and customize your browsing experience, use Safari extensions instead of web plug-ins.

Information about products not manufactured by Apple, or independent websites not controlled or tested by Apple, is provided without recommendation or endorsement. Apple assumes no responsibility with regard to the selection, performance, or use of third-party websites or products. Apple makes no representations regarding third-party website accuracy or reliability. Contact the vendor for additional information.

safari extension swift

Explore Apple Support Community

Find what’s been asked and answered by Apple customers.

View in English

Meet Safari Web Extensions on iOS

Safari extensions

Enhance and customize the web browsing experience on iPhone, iPad, and Mac with Safari extensions. Using powerful native APIs and frameworks, as well as familiar web technologies such as HTML, CSS, and JavaScript, you can easily create Safari extensions in Xcode and distribute them on the App Store in the Extensions category. Xcode 12 and later supports the popular WebExtension API and includes a porting tool to make it easy to bring your extensions to Safari.

Safari Web Extensions on MacOS, iPadOS, and iOS

Blocking content

Give users the ability to block certain content types on Safari iOS, iPadOS, and macOS. Built with Xcode, these app extensions are designed for speed and don’t slow down browsing. And because extensions never see what webpages users visit, user data is protected.

Learn about content blockers

Web extensions

Extend the web-browsing experience by allowing Safari to read and modify web page content. Now supported in iOS 15 and iPadOS 15, Safari web extensions are available on all Apple devices that support Safari. These extensions are built with Xcode and can communicate and share data with native apps — so you can integrate app content into Safari or send web data back to your app to create a unified experience.

Learn about Safari web extensions

Distributing and managing extensions

The Extensions category on the App Store for iPhone, iPad, and Mac showcases Safari extensions, with editorial spotlights and top charts to help people discover and download great extensions from the developer community. When your Safari extension is ready to be released, upload it to App Store Connect for distribution on the App Store. Apple reviews all extensions and updates to ensure they work reliably. Before submitting for review, make sure to read the guidelines for extensions .

Get started with App Store Connect

Converting extensions from other browsers

Web extensions that work in browsers other than Safari can be converted to support Safari on Apple platforms. Run the command-line web extension converter to create an Xcode project configured with a macOS app and/or iOS or iPadOS app that includes an extension that can be enabled in Safari.

Learn about converting a web extension for Safari

Upgrading macOS Safari web extensions to support iOS and iPadOS

It's easy to upgrade an existing macOS Safari web extension to also support iOS and iPadOS. Simply rerun your project through the command-line web extension converter tool with the --rebuild-project option. This will create a new Xcode project based on your existing project that includes extensions for these platforms.

Hands-On Mac 129: How To Use Safari Extensions All TWiT.tv Shows (Audio)

Safari, like any modern web browser, offers support for third-party extensions. In this episode of Hands on Mac, Mikah Sargent walks you through the process of discovering, managing, installing, and using extensions in the Safari browser on macOS Sonoma. Use Safari extensions on your Mac - https://support.apple.com/en-us/102343 Host: Mikah Sargent Want access to the video version and exclusive features? Become a member of Club TWiT today! https://twit.tv/clubtwit Club TWiT members can discuss this episode and leave feedback in the Club TWiT Discord.

  • Episode Website
  • More Episodes
  • This work is licensed under a Creative Commons License - Attribution-NonCommercial-NoDerivatives 4.0 International - http://creativecommons.org/licenses/by-nc-nd/4.0/

More by TWiT TV

COMMENTS

  1. Safari app extensions

    Safari app extensions use a combination of JavaScript, CSS, and native code written in Objective-C or Swift. Because you build Safari app extensions on the standard app extension model, you get many native app benefits: You bundle Safari app extensions inside your app and distribute them through the App Store.

  2. Creating a Safari web extension

    To create a new project in Xcode: In Xcode, choose File > New > Project. Select Multiplatform for your extension to work in both iOS and macOS, or select either the iOS or macOS platform for your extension to work for just that platform. In the Application section, click the Safari Extension App template. Click Next.

  3. Building a Safari app extension

    To create a Safari app extension: Launch Xcode and either open an existing project containing a macOS app or create a new one. Choose File > New > Target. From the list of templates in the Application Extension section, select Safari Extension, and click Next. Enter a product name for your extension, such as My Extension.

  4. Execute swift when safari extension is opened

    Running native Swift code at this point is not a problem if you keep a few things in mind. Create a default macOS app via Xcode: Add a new "Safari Extension" target to your app: Make sure that you have selected the correct type of Safari Extension. Because you want to run native Swift code, use the "Safari App Extension" type.

  5. How to Build a Safari App Extension in iOS 15

    If you already have an Xcode project, go to File->New->Target, and select Safari Extension (NOT Safari Extension App). Xcode will add a few boilerplate files in a new group: SafariWebExtensionHandler.swift is the glue between your native app and the JS code. It implements the NSExtensionRequestHandling protocol, which allows it to receive and ...

  6. How to create and use extensions

    Having to call trimmingCharacters(in:) every time is a bit wordy, so let's write an extension to make it shorter: extension String { func trimmed() -> String { self.trimmingCharacters(in: .whitespacesAndNewlines) } } Let's break that down…. We start with the extension keyword, which tells Swift we want to add functionality to an existing ...

  7. Swift extensions: An overview with examples

    Extensions in Swift are a powerful way to add your own functionality to types that you do not own. This overview of extensions and the examples herein are designed to help you understand how extensions work so you can implement and use them in your own Swift projects. Over 200k developers use LogRocket to create better digital experiences.

  8. Creating a browser extension for Safari and Chrome

    The container Swift project for Safari Another issue is how to manage the React/extension project with the container Swift project. The boilerplate extension resources (JavaScript/css, manifest and html files) created with a new Safari extension project are managed by Xcode.

  9. safari-extension · GitHub Topics · GitHub

    swift safari-extension userscript safari web-extension safari-app-extension userscript-editor Updated Feb 29, 2024; Swift; dgraham / Ka-Block Star 855. Code Issues Pull requests A Safari extension that blocks an artisanal selection of advertising domains. corporation safari-extension ...

  10. Running your Safari web extension

    First, enable the Develop menu in Safari: Choose Safari > Settings. Select the Advanced tab. Check the "Show Develop menu in menu bar" box, or the "Show features for web developers" box in Safari 17 or later. Then, in Safari 16 and earlier, choose Develop > Allow Unsigned Extensions.

  11. Creating a Safari App Extension

    The project for a Safari App Extensions contains at least two targets: The native macOS application which is the container for distribution. The Safari App Extension which will integrate with the Browser. Do not remove one or the other. Your App Extensions will neither run nor will it pass Apple's review process.

  12. Extensions in Swift: How and when to use them

    Extensions in Swift allow you to extend an existing class, struct, enumeration, or protocol with new functionality. Whether it's a custom type defined by you or a current type inside of a framework, extensions can create custom accessors and enhance the types you work with. So-called retroactive modeling allows you to extend types for which ...

  13. How-to Build an iOS Share Extension in Swift

    Initial Steps. Either create a new project, or open an existing one you'd like to add the extension to. Then hit File > New > Target. Under the iOS tab select Share Extension and press Next ...

  14. Use Safari extensions

    Use Safari extensions on your Mac. Safari extensions enhance and customize the browsing experience on your Mac. Here's how to install them, uninstall them, or share them across devices. Safari extensions add functionality to Safari, so you can explore the web the way you want. Extensions can show helpful information about a webpage, display ...

  15. Converting a web extension for Safari

    To see your converted extension in Safari, follow the instructions in Running your Safari web extension. Add iOS to your existing Xcode project. If you have an existing Xcode project with a macOS Safari web extension, and you want to add support for iOS to it, use the converter with the --rebuild-project option.

  16. Swift Protocols and Extensions

    Here is an example of using an extension to add a new method to the Int type in Swift: extension Int { func isEven() -> Bool { return self % 2 == 0 } } In this example, the isEven() method is ...

  17. Safari Extensions

    Web extensions. Extend the web-browsing experience by allowing Safari to read and modify web page content. Now supported in iOS 15 and iPadOS 15, Safari web extensions are available on all Apple devices that support Safari. These extensions are built with Xcode and can communicate and share data with native apps — so you can integrate app ...

  18. How to build an iOS Safari Web Extension

    But you actually want swipe out of the native app and go "Home" on your simulator or device and go to the Safari app. Tap the A A to open the Safari menu and toggle your extension on. Now when ...

  19. Create an iOS Share Extension with custom UI in Swift and ...

    Step 1: Add a Share Extension target to your project. Click the + Button or choose File New Target from Xcodes menu, then search for and select Share Extension. Enter a name and create the new target.

  20. swift

    When making the new target you should have selected Safari App Extension not Safari Web Extension (which is the default choice). If you did that, your folder structure would be different, for example you'd have SafariExtensionHandler.swift and SafariExtensionViewController.swift at the top level rather than SafariWebExtensionHandler.swift.

  21. Hands-On Mac 129: How To Use Safari Extensions

    Safari, like any modern web browser, offers support for third-party extensions. In this episode of Hands on Mac, Mikah Sargent walks you through the process of discovering, managing, installing, and using extensions in the Safari browser on macOS Sonoma. Use Safari extensions on your Mac - https:/…