Announcing Vizzly's Swift SDK for iOS and macOS

Visual regression testing is now available for native iOS and macOS apps. The Swift SDK brings Vizzly's TDD-focused visual testing workflow to XCTest, making it easy to catch UI bugs before they ship.

We’re excited to announce that Vizzly now supports iOS and macOS apps with our new Swift SDK. Visual regression testing is finally here for native app developers, with the same TDD-first workflow that web developers have been using.

If you’re an iOS developer who’s struggled with flaky UI tests or spent hours manually checking screens across different devices, this is for you.

How It Works

The Swift SDK integrates directly with XCTest, capturing screenshots from your real UI tests. Here’s what it looks like:

import XCTest
import Vizzly

class HomeScreenTests: XCTestCase {
    func testHomeScreen() {
        let app = XCUIApplication()
        app.launch()

        // Just add this line to your existing test
        app.vizzlyScreenshot(name: "home-screen")

        // Your regular test assertions continue...
        XCTAssertTrue(app.staticTexts["Welcome"].exists)
    }
}

Add one line to your test, and Vizzly captures the screenshot, compares it against your baseline, and shows you any visual changes.

Key Features

TDD Mode for Local Development

Run vizzly tdd start --open to review screenshots while you work. The CLI opens the dashboard at the URL it prints and picks an available port if the default is busy.

Local TDD compares screenshots on your machine using Honeydiff. You can use it without an account or API token.

Cloud Mode for CI/CD

When you’re ready to ship, Vizzly automatically switches to cloud mode for your CI pipeline. Set the VIZZLY_TOKEN environment variable in your GitHub Actions or Fastlane setup, and screenshots upload to the Vizzly cloud for team review.

The SDK handles mode switching automatically - no configuration changes needed between local and CI environments.

Native XCTest Integration

The SDK extends XCTest classes directly, so it feels natural in your test code:

// Screenshot the whole app
app.vizzlyScreenshot(name: "full-app")

// Screenshot a specific element
let navbar = app.navigationBars.firstMatch
navbar.vizzlyScreenshot(name: "navbar")

No new APIs to learn. No changes to how you write tests.

Multi-Device and Dark Mode Support

Test across different devices and appearance modes without extra configuration. Run your tests on iPhone SE, iPhone 15 Pro Max, and iPad - Vizzly creates separate baselines for each.

func testHomeScreenDarkMode() {
    let app = XCUIApplication()
    app.launchArguments = ["UIUserInterfaceStyle_Dark"]
    app.launch()

    app.vizzlyScreenshot(name: "home-screen")
}

Vizzly automatically captures device model, OS version, viewport dimensions, and scale factor for each screenshot.

Example: Testing a Product List

import XCTest
import Vizzly

class ProductListTests: XCTestCase {
    let app = XCUIApplication()

    override func setUp() {
        super.setUp()
        app.launch()
    }

    func testProductList() {
        // Navigate to product list
        app.tabBars.buttons["Products"].tap()

        // Wait for products to load
        XCTAssertTrue(app.tables.firstMatch.waitForExistence(timeout: 5))

        // Capture the full product list
        app.vizzlyScreenshot(name: "product-list")

        // Test a specific product card
        let firstProduct = app.tables.cells.firstMatch
        firstProduct.vizzlyScreenshot(name: "product-card")

        // Verify the functionality still works
        firstProduct.tap()
        XCTAssertTrue(app.staticTexts["Product Details"].exists)
    }

    func testProductListDarkMode() {
        app.launchArguments = ["UIUserInterfaceStyle_Dark"]
        app.launch()

        app.tabBars.buttons["Products"].tap()
        XCTAssertTrue(app.tables.firstMatch.waitForExistence(timeout: 5))

        app.vizzlyScreenshot(name: "product-list-dark")
    }

    func testProductListOnIPad() {
        // This test runs on iPad simulator
        app.launch()
        app.tabBars.buttons["Products"].tap()

        // Same screenshot name, different baseline for iPad
        app.vizzlyScreenshot(name: "product-list")
    }
}

CI/CD Integration

Here’s how to set it up in GitHub Actions:

name: UI Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: macos-latest

    steps:
      - uses: actions/checkout@v4

      - name: Run UI Tests
        env:
          VIZZLY_TOKEN: ${{ secrets.VIZZLY_TOKEN }}
        run: |
          xcodebuild test \
            -scheme MyApp \
            -destination 'platform=iOS Simulator,name=iPhone 15' \
            -testPlan MyAppUITests

Set the VIZZLY_TOKEN secret in your repo settings, and the SDK automatically switches to cloud mode for team review.

Getting Started

The Swift SDK is available now. Here’s how to get started:

  1. Install via Swift Package Manager: Add https://github.com/vizzly-testing/cli to your project
  2. Import in your UI tests: import Vizzly
  3. Add screenshots: app.vizzlyScreenshot(name: "screen-name")
  4. Run locally: vizzly tdd start for instant feedback
  5. Deploy to CI: Set VIZZLY_TOKEN in your environment

Check out the full documentation or follow the quickstart guide to get up and running in under 5 minutes.


The Swift SDK brings Vizzly’s visual testing workflow to iOS and macOS developers. Start using it today in TDD mode locally, or deploy it to your CI pipeline for team collaboration.

We’re excited to see what you build with it. If you have feedback or feature requests, open an issue on GitHub - we’re actively building based on developer feedback.

Ready to improve your visual workflow?

Start using Vizzly today and bring visual regression testing into the workflow described in this article.