Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ body:
- Brave
- Vivaldi
- Firefox (experimental)
- ChatGPT Atlas

validations:
required: false
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ SimplyTrack requires several macOS permissions to function properly:

1. **Automation Permission**: To track browser activity
- System Preferences → Privacy & Security → Automation
- Enable SimplyTrack for your browsers (Safari, Chrome, Edge, Arc, Brave, Vivaldi, Firefox)
- Enable SimplyTrack for your browsers (Safari, Chrome, Edge, Arc, Brave, Vivaldi, Firefox, ChatGPT Atlas)

2. **System Events Permission**: For Safari and Firefox browser integration
- System Preferences → Privacy & Security → Automation
Expand Down
2 changes: 2 additions & 0 deletions SimplyTrack/Managers/PermissionManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class PermissionManager: ObservableObject {
"com.brave.Browser",
"com.vivaldi.Vivaldi",
"org.mozilla.firefox",
"com.openai.atlas",
"com.openai.atlas.web",
]

private init() {
Expand Down
55 changes: 55 additions & 0 deletions SimplyTrack/Services/Browsers/AtlasBrowser.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// AtlasBrowser.swift
// SimplyTrack
//

import Foundation

/// ChatGPT Atlas-specific implementation of browser interface.
/// Handles URL detection and incognito mode detection for ChatGPT Atlas.
/// Atlas is Chromium-based and shares the same AppleScript interface as Chrome.
class AtlasBrowser: BaseBrowser {
static let appBundleId = "com.openai.atlas"
static let webBundleId = "com.openai.atlas.web"
static let supportedBundleIds = [appBundleId, webBundleId]

init() {
super.init(bundleId: Self.appBundleId, displayName: "ChatGPT Atlas")
}

/// ChatGPT Atlas-specific AppleScript for URL retrieval
override var currentURLScript: String {
return """
tell application id "\(Self.webBundleId)"
if (count of windows) > 0 then
set currentTab to active tab of window 1
return URL of currentTab
end if
end tell
"""
}

/// Checks if ChatGPT Atlas is currently in incognito mode.
/// Uses the 'mode' property available in Atlas's Chromium AppleScript interface.
/// Note: Permissions are already verified by getCurrentURL() call, so no need to re-check.
/// - Returns: true if incognito mode is detected, false otherwise
override func isInPrivateBrowsingMode() -> Bool {
let script = """
tell application id "\(Self.webBundleId)"
if (count of windows) > 0 then
return mode of window 1 is equal to "incognito"
end if
end tell
"""

let scriptResult = executeAppleScript(script)

guard let result = scriptResult.result,
let isIncognito = Bool(result.lowercased())
else {
return false
}

return isIncognito
}
}
34 changes: 22 additions & 12 deletions SimplyTrack/Services/WebTrackingService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// SimplyTrack
//
// Handles browser integration, AppleScript execution, favicon fetching, and website detection
// Supports Safari, Chrome, Edge, Arc, Brave, Vivaldi, and Firefox through AppleScript communication for website tracking
// Supports Safari, Chrome, Edge, Arc, Brave, Vivaldi, Firefox, and ChatGPT Atlas through AppleScript communication for website tracking
//

import AppKit
Expand Down Expand Up @@ -56,17 +56,27 @@ actor FaviconCacheActor {

class WebTrackingService {

private let browsers: [String: BrowserInterface] = [
SafariBrowser(),
ChromeBrowser(),
EdgeBrowser(),
ArcBrowser(),
BraveBrowser(),
VivaldiBrowser(),
FirefoxBrowser(),
].reduce(into: [:]) { result, browser in
result[browser.bundleId] = browser
}
private let browsers: [String: BrowserInterface] = {
let atlasBrowser = AtlasBrowser()
var browsers = [
SafariBrowser(),
ChromeBrowser(),
EdgeBrowser(),
ArcBrowser(),
BraveBrowser(),
VivaldiBrowser(),
FirefoxBrowser(),
atlasBrowser,
].reduce(into: [String: BrowserInterface]()) { result, browser in
result[browser.bundleId] = browser
}

for bundleId in AtlasBrowser.supportedBundleIds {
browsers[bundleId] = atlasBrowser

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have evidence that NSWorkspace.frontmostApplication.bundleIdentifier can return com.openai.atlas.web? If the frontmost app is always the visible wrapper com.openai.atlas, then we should keep only com.openai.atlas for browser detection and use com.openai.atlas.web only as the AppleScript target/entitlement.

}

return browsers
}()

private let faviconCacheActor = FaviconCacheActor()

Expand Down
2 changes: 2 additions & 0 deletions SimplyTrack/SimplyTrack.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
<string>com.brave.Browser</string>
<string>com.vivaldi.Vivaldi</string>
<string>org.mozilla.firefox</string>
<string>com.openai.atlas</string>

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the wrapper app id in AppleEvents entitlements? AtlasBrowser now targets tell application id "com.openai.atlas.web", so com.openai.atlas.web seems to be the required sandbox exception. com.openai.atlas still makes sense for frontmost-app detection, but I do not see an AppleEvent call targeting it.

<string>com.openai.atlas.web</string>
<string>com.apple.systemevents</string>
</array>
<key>com.apple.security.temporary-exception.files.home-relative-path.read-only</key>
Expand Down
32 changes: 32 additions & 0 deletions SimplyTrackTests/BrowserSupportTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// BrowserSupportTests.swift
// SimplyTrackTests
//
// Created by Hermes Agent on 06.05.2026.
//

import Testing

@testable import SimplyTrack

struct BrowserSupportTests {

@Test func chatGPTAtlasIsRecognizedAsSupportedBrowser() {
let service = WebTrackingService()

let browser = service.getBrowser(for: "com.openai.atlas")

#expect(browser != nil)
#expect(browser?.bundleId == "com.openai.atlas")
}

@Test func chatGPTAtlasWebProcessIsRecognizedAsSupportedBrowser() {
let service = WebTrackingService()

let browser = service.getBrowser(for: "com.openai.atlas.web")

#expect(browser != nil)
#expect(browser?.bundleId == "com.openai.atlas")
#expect(browser?.displayName == "ChatGPT Atlas")
}
}
Loading