Safari browser extension development

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1212
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    815

Safari Extension Development

Safari Extension is technically the most complex browser extension. Apple requires a native Mac/iOS wrapper, signing via Apple Developer Program, and App Store approval. However, it's the only legal way to extend Safari — especially on iOS, where Safari remains the only browser for any WebKit engine.

Architectural options

Safari Web Extension (modern, since Safari 14+) — based on WebExtensions API, similar to Chrome/Firefox. Requires wrapping in a native Mac/iOS app. This is the main recommended format since 2020.

Safari App Extension (deprecated) — native Swift/ObjC code with native extension points. More capabilities (access to native APIs), but significantly more complex.

Content Blocker — simplified format for blocking content via JSON rules only. Doesn't require JavaScript, works on iOS. Used for ad blockers.

Project structure

Safari Web Extension is an Xcode project where the extension is an app target extension:

MyApp.xcodeproj
├── MyApp/                   # Main wrapper application
│   ├── AppDelegate.swift
│   └── ContentView.swift    # Minimal UI (activation instructions)
└── MyApp Extension/         # The extension itself
    ├── manifest.json
    ├── background.js
    ├── content.js
    ├── popup.html
    └── Resources/
        └── icons/

Converting Chrome Extension to Safari

Apple provides the safari-web-extension-converter tool:

# Install Xcode (required) and xcrun
xcrun safari-web-extension-converter \
  ./my-chrome-extension \
  --project-location ./safari-project \
  --app-name "My Extension" \
  --bundle-identifier com.example.my-extension \
  --swift

The converter creates an Xcode project with a native wrapper and copies all extension files. After that, you need to:

  1. Fix incompatible APIs (list below)
  2. Configure app icons (requires set of 10+ sizes)
  3. Sign via Apple Developer account

Manifest V2 vs V3 in Safari

Version Safari Status
MV2 Safari 14–17 Works, deprecated
MV3 Safari 15.4+ Recommended

Safari 15.4 added MV3 support. For maximum compatibility with iOS 15+, we use MV3.

Incompatible APIs and workarounds

// chrome.* does NOT work in Safari — use browser.* or polyfill
// webextension-polyfill solves most problems

import browser from 'webextension-polyfill';

// Does NOT work in Safari:
// chrome.scripting.executeScript (MV3) — partial from Safari 16
// chrome.declarativeNetRequest — from Safari 15.4
// chrome.sidePanel — Chrome only

// Works in Safari:
// browser.storage.local / sync
// browser.tabs
// browser.runtime.sendMessage
// browser.webNavigation
// browser.cookies (with permission)

Safari specifics:

  • browser.storage.sync works via iCloud — syncs between Mac and iPhone/iPad
  • Content Security Policy is stricter in Safari — some eval-dependent libraries don't work
  • Background Service Worker — Safari sometimes terminates SW aggressively, need to reinitialize state

iOS extensions

Safari on iOS supports extensions starting from iOS 15. This opens a unique market unavailable for Chrome/Firefox extensions:

// SafariExtensionViewController.swift — native code for iOS part
import SafariServices

class SafariExtensionViewController: SFSafariExtensionViewController {
    static let shared = SafariExtensionViewController()

    // Called when opening popup in Safari on iOS
    override func viewDidLoad() {
        super.viewDidLoad()
        // Embedded WebView with popup.html loads automatically
    }
}
// JavaScript → Native Bridge
// From content script, you can call native code via:
browser.runtime.sendNativeMessage('com.example.app', { type: 'DO_NATIVE_THING' });

Signing and publishing

# Build for testing (development signing)
xcodebuild -scheme "MyApp" -configuration Debug \
  -destination "platform=macOS" build

# Archive for App Store
xcodebuild -scheme "MyApp" -configuration Release \
  -archivePath build/MyApp.xcarchive archive

xcodebuild -exportArchive \
  -archivePath build/MyApp.xcarchive \
  -exportPath build/export \
  -exportOptionsPlist ExportOptions.plist

Requirements for publishing:

  • Apple Developer Program ($99/year)
  • Signing for Mac App + Safari Extension entitlements
  • App Review (~1–3 days for updates, up to 7 days for new)
  • Minimum main app functionality — App Store won't accept "empty" wrappers

Device testing

# Mac: enable Developer Mode
# Safari → Preferences → Extensions → Show "Develop" menu
# Develop → Allow unsigned extensions

# iOS: Settings → Safari → Extensions (appears after app installation)

Manifest structure for Safari MV3

{
  "manifest_version": 3,
  "name": "My Safari Extension",
  "version": "1.0",
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [{
    "matches": ["https://*.example.com/*"],
    "js": ["content.js"],
    "run_at": "document_idle"
  }],
  "action": {
    "default_popup": "popup.html",
    "default_icon": "icons/toolbar-icon.svg"
  },
  "permissions": ["storage", "activeTab"],
  "browser_specific_settings": {
    "safari": {
      "strict_min_version": "15.4"
    }
  }
}

Common issues and solutions

Issue: Service Worker terminates too quickly. Solution: Don't store state in SW memory, use chrome.storage.session (Safari 16.4+) or reinitialize on each start.

Issue: fetch in Content Script is blocked by CORS. Solution: Redirect request through Background (browser.runtime.sendMessage), as Background bypasses CORS restrictions from the page.

Issue: Extension doesn't appear on iOS. Solution: App must be installed and launched at least once. Extension is enabled manually in Settings → Safari → Extensions.

Timeline

Converting ready Chrome extension to Safari with fixing incompatibilities and Mac App Store publication — 5–8 working days. Developing cross-platform extension (Mac + iOS) from scratch, including native wrappers, testing, and App Review — 15–25 days. Main time — Xcode setup, Apple Developer bureaucracy, and App Review waiting.