Ora Browser is built by developers, for developers. With native support for WebKit’s developer tools, custom keyboard shortcuts, and advanced debugging features, Ora makes web development seamless.
Web Inspector
Ora enables WebKit’s full developer tools suite by default, giving you access to powerful debugging capabilities.
Developer extras are enabled automatically when creating any WebView:
func customWKConfig ( containerId : UUID, temporaryStorage : Bool = false ) -> WKWebViewConfiguration {
let configuration = WKWebViewConfiguration ()
// Enable Developer Tools
configuration. preferences . setValue ( true , forKey : "developerExtrasEnabled" )
configuration. preferences . setValue ( true , forKey : "javaScriptEnabled" )
configuration. preferences . setValue ( true , forKey : "javaScriptCanOpenWindowsAutomatically" )
return configuration
}
Making WebViews Inspectable
All WebViews in Ora are marked as inspectable for external debugging:
webView. isInspectable = true
With isInspectable enabled, you can attach Safari’s Web Inspector or other debugging tools to inspect any Ora tab.
Opening the Inspector
Right-click anywhere on a webpage and select Inspect Element to open the Web Inspector.
Right-click on any element
Use the context menu to access developer tools
Select 'Inspect Element'
Opens the Web Inspector focused on the selected element
Use the Inspector panels
Access Elements, Console, Sources, Network, and more
Inspector Features
Elements Panel Inspect and modify the DOM structure and CSS styles in real-time
Console Execute JavaScript, view logs, and debug runtime errors
Network Panel Monitor network requests, response times, and resource loading
Sources Debug JavaScript with breakpoints, step execution, and call stack inspection
JavaScript Console
Access the JavaScript console to debug scripts and inspect page state.
Console Logging
All console methods are available:
console.log() - Standard logging
console.error() - Error messages
console.warn() - Warnings
console.info() - Informational messages
console.debug() - Debug messages
console.table() - Tabular data display
Executing JavaScript
Run JavaScript directly in the console or programmatically:
webView. evaluateJavaScript ( "document.title" ) { result, error in
if let title = result as? String {
print ( "Page title: \( title ) " )
}
}
JavaScript Configuration
Ora provides full JavaScript support with modern features enabled:
// Enable JavaScript
configuration. preferences . setValue ( true , forKey : "javaScriptEnabled" )
configuration. preferences . setValue ( true , forKey : "javaScriptCanOpenWindowsAutomatically" )
// Security: Prevent automatic window opening
configuration. preferences . javaScriptCanOpenWindowsAutomatically = false
// Enable modern JavaScript features
let preferences = WKWebpagePreferences ()
preferences. allowsContentJavaScript = true
configuration. defaultWebpagePreferences = preferences
Script Message Handlers
Ora implements custom JavaScript message handlers for advanced page interaction.
URL and Title Updates
Capture URL and title changes from JavaScript:
class TabScriptHandler : NSObject , WKScriptMessageHandler {
func userContentController ( _ userContentController : WKUserContentController, didReceive message : WKScriptMessage) {
if message.name == "listener" {
guard let jsonString = message.body as? String ,
let jsonData = jsonString. data ( using : . utf8 )
else { return }
do {
let update = try JSONDecoder (). decode (URLUpdate. self , from : jsonData)
DispatchQueue. main . async {
guard let tab = self .tab else { return }
tab. title = update. title
tab. url = URL ( string : update. href ) ?? tab. url
tab. setFavicon ()
tab. updateHistory ()
}
} catch {
logger. error ( "Failed to decode JS message: \( error. localizedDescription ) " )
}
}
}
}
Link Hover Detection
Capture hovered links for preview:
if message.name == "linkHover" {
let hovered = message. body as? String
DispatchQueue. main . async {
guard let tab = self .tab else { return }
let trimmed = (hovered ?? "" ). trimmingCharacters ( in : . whitespacesAndNewlines )
tab. hoveredLinkURL = trimmed. isEmpty ? nil : trimmed
}
}
Monitor media playback events:
if message.name == "mediaEvent" {
guard let body = message.body as? String ,
let data = body. data ( using : . utf8 ),
let tab = self .tab
else { return }
if let payload = try ? JSONDecoder (). decode (MediaEventPayload. self , from : data) {
DispatchQueue. main . async { [ weak self ] in
self ? . mediaController ? . receive ( event : payload, from : tab)
}
}
}
Registering Message Handlers
let contentController = WKUserContentController ()
contentController. add ( self , name : "listener" )
contentController. add ( self , name : "linkHover" )
contentController. add ( self , name : "mediaEvent" )
configuration. userContentController = contentController
Ora configures WebViews for optimal performance:
Hardware Acceleration
// Enable layer-backed view for hardware acceleration
webView. wantsLayer = true
webView. isInspectable = true
if let layer = webView.layer {
layer. isOpaque = true
layer. drawsAsynchronously = true
}
Process Pool Management
// Enable process pool for better memory management
let processPool = WKProcessPool ()
configuration. processPool = processPool
GPU Acceleration
let preferences = WKWebpagePreferences ()
preferences. allowsContentJavaScript = true
configuration. defaultWebpagePreferences = preferences
Picture-in-Picture Support
configuration. preferences . setValue ( true , forKey : "allowsPictureInPictureMediaPlayback" )
configuration. allowsAirPlayForMediaPlayback = true
configuration. preferences . isElementFullscreenEnabled = true
Autoplay Configuration
// Enable media playback without user interaction
configuration. mediaTypesRequiringUserActionForPlayback = []
func togglePiP ( _ currentTab : Tab ? , _ oldTab : Tab ? ) {
if currentTab ? .id != oldTab ? .id, SettingsStore.shared.autoPiPEnabled {
currentTab ? . webView . evaluateJavaScript ( "window.__oraTriggerPiP(true)" )
oldTab ? . webView . evaluateJavaScript ( "window.__oraTriggerPiP()" )
}
}
Custom User Agent
Ora uses a modern Safari user agent string for maximum compatibility:
let userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0.1 Safari/605.1.15"
configuration. applicationNameForUserAgent = userAgent
Navigation Gestures
Enable intuitive navigation for development testing:
webView. allowsMagnification = true
webView. allowsBackForwardNavigationGestures = true
URL Construction Utilities
Ora provides utilities for constructing and validating URLs:
func loadURL ( _ urlString : String ) {
lastAccessedAt = Date ()
let input = urlString. trimmingCharacters ( in : . whitespacesAndNewlines )
// Try to construct a direct URL
if let directURL = constructURL ( from : input) {
webView. load ( URLRequest ( url : directURL))
return
}
// Otherwise, treat as search query
let searchEngineService = SearchEngineService ()
if let engine = searchEngineService. getDefaultSearchEngine ( for : self . container . id ),
let searchURL = searchEngineService. createSearchURL ( for : engine, query : input)
{
webView. load ( URLRequest ( url : searchURL))
return
}
// Fallback to Google search
if let fallbackURL = URL ( string : "https://www.google.com/search?q="
+ (input. addingPercentEncoding ( withAllowedCharacters : . urlQueryAllowed ) ?? "" ))
{
webView. load ( URLRequest ( url : fallbackURL))
}
}
Custom Keyboard Shortcuts
Ora supports custom keyboard shortcuts for development workflows.
Default Developer Shortcuts
Action Shortcut Reload Page ⌘RHard Reload (Clear Cache) ⌘⇧RClear Cookies & Reload ⌘⌥⇧RFind in Page ⌘FToggle Sidebar ⌘⌥SToggle Toolbar ⌘⌥T
Custom Shortcut Manager
@Published var customKeyboardShortcuts: [ String : KeyChord] {
didSet { saveCodable (customKeyboardShortcuts, forKey : customKeyboardShortcutsKey) }
}
func setCustomKeyboardShortcut ( id : String , keyChord : KeyChord) {
var shortcuts = customKeyboardShortcuts
shortcuts[id] = keyChord
customKeyboardShortcuts = shortcuts
}
Navigation Commands
Access common development actions through the menu system:
CommandMenu ( "Navigation" ) {
Button ( "Reload Page" ) {
NotificationCenter. default . post ( name : . reloadPage , object : NSApp. keyWindow )
}
. keyboardShortcut ( "r" , modifiers : . command )
Button ( "Clear Cache & Reload" ) {
NotificationCenter. default . post ( name : . clearCacheAndReload , object : NSApp. keyWindow )
}
. keyboardShortcut ( "r" , modifiers : [. command , . shift ])
Button ( "Clear Cookies & Reload" ) {
NotificationCenter. default . post ( name : . clearCookiesAndReload , object : NSApp. keyWindow )
}
. keyboardShortcut ( "r" , modifiers : [. command , . option , . shift ])
}
Error Handling
Ora provides comprehensive error handling for navigation failures:
func setNavigationError ( _ error : Error , for url : URL ? ) {
DispatchQueue. main . async {
self . hasNavigationError = true
self . navigationError = error
self . failedURL = url
}
}
func clearNavigationError () {
DispatchQueue. main . async {
self . hasNavigationError = false
self . navigationError = nil
self . failedURL = nil
}
}
func retryNavigation () {
if let url = failedURL {
let request = URLRequest ( url : url)
webView. load (request)
}
}
Best Practices for Developers
Use Web Inspector Right-click and select “Inspect Element” for full access to WebKit’s debugging tools
Test with Spaces Create separate Spaces for different testing environments (production, staging, local)
Monitor the Console Keep the console open to catch JavaScript errors and network issues early
Custom Shortcuts Configure custom keyboard shortcuts for your most common development tasks
Advanced Features
Download Manager Integration
Ora includes a built-in download manager for testing file downloads:
init (
id : UUID = UUID (),
url : URL,
title : String ,
container : TabContainer,
downloadManager : DownloadManager ? = nil ,
isPrivate : Bool
) {
self . downloadManager = downloadManager
// ... initialization
}
History Manager for Testing
Track browsing history during development:
func updateHistory () {
if let historyManager = self .historyManager {
Task { @MainActor in
historyManager. record (
title : self . title ,
url : self . url ,
faviconURL : self . favicon ,
faviconLocalFile : self . faviconLocalFile ,
container : self . container
)
}
}
}
Debug media playback with integrated media controls:
func stopMedia ( completed : @escaping () -> Void ) {
let js = """
document.querySelectorAll('video, audio').forEach(el => {
try {
el.pause();
el.src = '';
el.load();
} catch (e) {}
});
"""
webView. evaluateJavaScript (js) { _ , _ in
self . webView . closeAllMediaPresentations ( completionHandler : completed)
}
}
Developer tools can impact page performance. For accurate performance testing, disable the inspector when measuring load times or rendering performance.
Future Development Features
Ora is actively developing additional developer features:
Extension Support - Safari and Chrome extension compatibility (in development)
Network Throttling - Simulate different network conditions
Device Emulation - Test responsive designs with device profiles
Local Override - Override network requests with local files
Check the roadmap for the latest development features.