diff --git a/docs/src/content/docs/tutorials/02-sparkle-updates.mdx b/docs/src/content/docs/tutorials/02-sparkle-updates.mdx
new file mode 100644
index 000000000..2d62cd752
--- /dev/null
+++ b/docs/src/content/docs/tutorials/02-sparkle-updates.mdx
@@ -0,0 +1,499 @@
+---
+title: Integrating Sparkle for Self-Updates
+description: A tutorial on integrating Sparkle for automatic updates in macOS and Windows applications
+---
+
+import { Tabs, TabItem, FileTree } from '@astrojs/starlight/components';
+import {Image } from 'astro:assets';
+
+import gatekeeper from "../../../assets/sparkle/gatekeeper.png";
+import openprompt from "../../../assets/sparkle/openprompt.png";
+import prefs from "../../../assets/sparkle/prefs.png";
+import touchid from "../../../assets/sparkle/touchid.png";
+import winsparkle from "../../../assets/sparkle/winsparkle-screenshot.png";
+import updater3 from "../../../assets/sparkle/updater3.mp4";
+
+
+[Sparkle](https://sparkle-project.org/) provides all the functionality needed for updating applications. It handles:
+
+- Checking for updates (automatically or manually)
+- Downloading updates
+- Verifying update integrity with cryptographic signatures
+- Installing updates with user consent
+
+:::note
+For this tutorial, an [Apple developer certificate](https://developer.apple.com/help/account/create-certificates/create-developer-id-certificates) is required.
+:::
+
+## Tutorial: Integrating Sparkle with Wails
+
+This tutorial will walk you through the complete process of adding self-update capabilities to your Wails application using Sparkle. We'll cover:
+
+1. Installing the Sparkle framework
+2. Integrating with go-sparkle
+3. Setting up a local development server for testing updates
+4. Creating and signing update packages
+5. Configuring the appcast.xml file
+
+
+By the end of the tutorial, you'll know how to integrate Sparkle into your Wails application. Here is a demo:
+
+
+
+
+### Step 1: Installing the Sparkle Framework
+
+First, we need to download and integrate the Sparkle framework into our application bundle.
+
+#### Download Sparkle Framework
+
+1. Download the latest Sparkle package [from GitHub](https://github.com/sparkle-project/Sparkle/releases)
+2. Extract the downloaded archive
+3. For this tutorial, we're using [Sparkle 2.6.4](https://github.com/sparkle-project/Sparkle/releases/tag/2.6.4)
+
+The extracted Sparkle package contains several important directories and files:
+
+
+- CHANGELOG
+- INSTALL
+- LICENSE
+- SampleAppcast.xml
+- Sparkle Test App.app
+- Sparkle.framework/
+ - Autoupdate -> Versions/Current/Autoupdate
+ - Headers -> Versions/Current/Headers
+ - Modules -> Versions/Current/Modules
+ - PrivateHeaders -> Versions/Current/PrivateHeaders
+ - Resources -> Versions/Current/Resources
+ - Sparkle -> Versions/Current/Sparkle
+ - Updater.app -> Versions/Current/Updater.app
+ - Versions/
+ - XPCServices -> Versions/Current/XPCServices
+- Symbols/
+ - Various .dSYM files
+- bin/
+ - BinaryDelta
+ - generate_appcast
+ - generate_keys
+ - old_dsa_scripts
+ - sign_update
+- sparkle.app
+
+
+#### Add Sparkle Framework to Your App
+
+1. Create a `Frameworks` directory in your `build/darwin` folder:
+
+```shell
+mkdir -p build/darwin/Frameworks
+```
+
+2. Copy the Sparkle framework to your `build/darwin` folder:
+
+```shell
+cp -R /path/to/Sparkle-2.6.4/Sparkle.framework build/darwin/Frameworks
+```
+
+:::note
+The `Frameworks` directory is the standard location for frameworks within macOS applications. When examining existing applications (via right-click > Show Package Contents), you'll find frameworks in paths like `/Applications/AppName.app/Contents/Frameworks/`.
+:::
+
+#### Update Build Configuration
+
+Modify your `build/darwin/Taskfile.yml` to copy the Sparkle framework into your app bundle:
+
+```diff
+ create:app:bundle:
+ summary: Creates an `.app` bundle
+ cmds:
+ - mkdir -p {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/{MacOS,Resources,Frameworks}
+ - cp build/icons.icns {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/Resources
+ - cp {{.BIN_DIR}}/{{.APP_NAME}} {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/MacOS
+ - cp build/darwin/Info.plist {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents
++ - cp -R build/darwin/Frameworks/Sparkle.framework {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/Frameworks
+```
+
+#### Set up CGO_LDFLAGS
+
+Under the `env` block of the `build` task in `build/darwin/Taskfile.yml`, add:
+
+```diff
+ env:
+ CGO_ENABLED: 1
+ CGO_CFLAGS: -mmacosx-version-min=10.13
+- CGO_LDFLAGS: -mmacosx-version-min=10.13
++ CGO_LDFLAGS: -mmacosx-version-min=10.13 -rpath @loader_path/../Frameworks
+```
+
+This path is relative to where our binary will be inside the app bundle:
+
+
+ - YourApp.app/
+ - Contents/
+ - MacOS/
+ - YourApp
+ - Frameworks/
+ - Sparkle.framework/
+
+
+#### Update Info.plist
+
+Add the following keys to your `build/darwin/Info.plist` file:
+
+```xml
+SUFeedURL
+https://localhost/appcast.xml
+SUEnableAutomaticChecks
+
+```
+
+We'll generate and add the public key in a later step.
+
+#### Test Build
+
+Now, we will test that building the app bundle works. To do this, run:
+
+```shell
+wails3 package
+```
+
+If the build was successful, the app bundle should contain the Sparkle framework:
+
+
+ - YourApp.app/
+ - Contents/
+ - MacOS/
+ - YourApp
+ - Frameworks/
+ - Sparkle.framework/
+
+
+You can check this by right clicking on the app bundle and selecting "Show Package Contents".
+
+
+### Step 2: Integrating with go-sparkle
+
+Now that we have the Sparkle framework installed, let's integrate it with our Go code using the [go-sparkle](https://github.com/abemedia/go-sparkle) package.
+
+#### Install go-sparkle
+
+Add the go-sparkle package to your project:
+
+```shell
+go get github.com/abemedia/go-sparkle
+```
+
+#### Basic Integration
+
+In your `main.go` file, import `go-sparkle` with a leading underscore:
+
+```go
+import (
+ _ "github.com/abemedia/go-sparkle"
+)
+```
+
+#### Rebuild your Application
+
+To rebuild your application, run:
+
+```shell
+wails3 package
+```
+
+If all is successful, you should be able to run your application and get a popup dialog asking if you want to enable automatic updates.
+
+TBD: PICTURE
+
+
+### Step 3: Setting up a Local Development Server
+
+To test the update mechanism, we need a server to host our update files. We'll use [Caddy](https://caddyserver.com/) for this purpose as it provides excellent HTTPS support.
+
+#### Install Caddy
+
+Install Caddy using Homebrew:
+
+```shell
+brew install caddy
+```
+
+#### Create Updates Directory
+
+Create an `updates` directory to host your update files:
+
+```shell
+mkdir -p build/darwin/updates
+```
+
+#### Create a Caddyfile
+
+Create a file named `Caddyfile` in your project directory with:
+
+```
+localhost {
+ root * ./build/darwin/updates
+ file_server
+}
+```
+
+#### Create a test html file
+
+Create an html file to test the server:
+
+```shell
+echo "Hello World" > build/darwin/updates/index.html
+```
+
+#### Start the Server
+
+Start Caddy with:
+
+```shell
+caddy run
+```
+
+If you now browse to `https://localhost`, you should see the test HTML file.
+
+### Step 4: Creating and Signing Updates
+
+Sparkle uses cryptographic signatures to verify update integrity. Let's set up the necessary keys and learn how to sign updates.
+
+#### Generate Sparkle Keys
+
+Use the `generate_keys` tool from the Sparkle package:
+
+```shell
+/path/to/Sparkle-2.6.4/bin/generate_keys
+```
+
+When running this tool for the first time, you may encounter macOS Gatekeeper security prompts:
+
+
+
+To proceed, open System Settings > Privacy & Security and scroll to the bottom:
+
+:::note
+The naming above is as of macOS Sequoia 15.3. Previous versions of macOS may differ.
+:::
+
+
+
+Click "Allow Anyway" and then run the tool again. You'll see another prompt:
+
+
+
+Click "Open Anyway" and authenticate:
+
+
+
+After authentication, the tool will generate a key pair and output your public key:
+
+```
+$ ./bin/generate_keys
+Generating a new signing key. This may take a moment, depending on your machine.
+A key has been generated and saved in your keychain. Add the `SUPublicEDKey` key to
+the Info.plist of each app for which you intend to use Sparkle for distributing
+updates. It should appear like this:
+
+ SUPublicEDKey
+ wiI5O/SGcbX9VdcIN+hBXvV66KI3gpTTlHMelslKsg0=
+```
+
+This will generate two keys:
+- A private key (kept secure in your keychain)
+- A public key (add this to your Info.plist)
+
+Update your `build/darwin/Info.plist` with the generated public key:
+
+```xml
+SUPublicEDKey
+GENERATED_PUBLIC_KEY
+```
+
+#### Create a Test Update
+
+1. Firstly, rename your existing application to `oldversion.app`.
+2. Make a change to your existing application. For our demo app, we'll update the version number text to 1.0.0.
+3. Build the updated application using `wails3 package`
+4. Code sign the updated application:
+
+Check if you have a valid developer identity by running `security find-identity -v -p codesigning` which should show any valid identities in the format of Developer ID Application: Human Person (TEAMIDHERE)".
+
+
+
+```shell
+CODE_SIGN_IDENTITY="Developer ID Application: Human Person (TEAMIDHERE)"
+
+codesign -f -s "$CODE_SIGN_IDENTITY" -o runtime bin/updater3.app/Contents/Frameworks/Sparkle.framework/Versions/B/XPCServices/Installer.xpc
+
+# For Sparkle versions >= 2.6
+codesign -f -s "$CODE_SIGN_IDENTITY" -o runtime --preserve-metadata=entitlements bin/updater3.app/Contents/Frameworks/Sparkle.framework/Versions/B/XPCServices/Downloader.xpc
+
+# For Sparkle versions < 2.6
+#codesign -f -s "$CODE_SIGN_IDENTITY" -o runtime --entitlements Entitlements/Downloader.entitlements bin/updater3.app/Contents/Frameworks/Sparkle.framework/Versions/B/XPCServices/Downloader.xpc
+
+codesign -f -s "$CODE_SIGN_IDENTITY" -o runtime bin/updater3.app/Contents/Frameworks/Sparkle.framework/Versions/B/Autoupdate
+codesign -f -s "$CODE_SIGN_IDENTITY" -o runtime bin/updater3.app/Contents/Frameworks/Sparkle.framework/Versions/B/Updater.app
+codesign -f -s "$CODE_SIGN_IDENTITY" -o runtime bin/updater3.app/Contents/Frameworks/Sparkle.framework
+```
+5. Create a ZIP archive of the updated application:
+
+```shell
+ditto -c -k --keepParent "bin/YourApp.app" "build/darwin/updates/YourApp_1.0.0.zip"
+```
+
+#### Sign the Update
+
+Sign the update using the `sign_update` tool:
+
+```shell
+/path/to/Sparkle-2.6.4/bin/sign_update updates/YourApp_1.0.0.zip /path/to/your/private/key
+```
+
+This will output a signature that you'll need for your appcast.xml file.
+
+### Step 5: Creating the Appcast.xml File
+
+The appcast.xml file is an RSS feed that tells Sparkle where to find updates and what versions are available.
+
+Create an `appcast.xml` file in your `updates` directory:
+
+```xml
+
+
+
+ YourApp Changelog
+ http://localhost:8000/appcast.xml
+ Most recent changes with links to updates.
+ en
+
+ Version 1.0.0
+ 1.0.0
+
+ New Features
+
+
Feature 1
+
Feature 2
+
+
Bug Fixes
+
+
Fix 1
+
Fix 2
+
+ ]]>
+
+ Wed, 01 Mar 2023 12:00:00 +0000
+
+
+
+
+```
+
+Replace `YOUR_SIGNATURE_FROM_SIGN_UPDATE` with the signature generated in the previous step.
+
+#### Automating Appcast Generation
+
+For convenience, you can use the `generate_appcast` tool to automatically generate the appcast.xml file:
+
+```shell
+/path/to/Sparkle-2.6.4/bin/generate_appcast \
+ --download-url-prefix "http://localhost:8000" \
+ --private-key-path /path/to/your/private/key \
+ updates/
+```
+
+This will scan the updates directory and generate an appcast.xml file with the correct signatures.
+
+### Step 6: Testing the Update Process
+
+Now that everything is set up, let's test the update process:
+
+1. Build and run your application with version 0.9.0
+2. The app should check for updates and find version 1.0.0
+3. Sparkle will prompt the user to update
+4. After confirmation, Sparkle will download and install the update
+
+## Additional Configuration
+
+### Customising Update Checks
+
+You can customise how Sparkle checks for updates by adding additional keys to your Info.plist:
+
+```xml
+
+SUScheduledCheckInterval
+86400
+
+
+SUSkipMinorUpdates
+
+```
+
+### Adding Manual Update Checks
+
+To provide a manual update check option, add a function like this to your application service:
+
+```go
+func (a *App) CheckForUpdates() {
+ sparkle.CheckForUpdates()
+}
+```
+
+Then, expose this function to your frontend:
+
+```go
+//go:embed all:frontend/dist
+var assets embed.FS
+
+func main() {
+ // Create application with options
+ app := wails.NewApplication(wails.Options{
+ Assets: assets,
+ Bind: []interface{}{
+ &App{},
+ },
+ })
+
+ // Run the application
+ err := app.Run()
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+```
+
+For a native macOS experience, add a menu item under ` -> Check for Updates` that calls this function.
+
+### Windows Support with WinSparkle
+
+For Windows applications, you can use WinSparkle, which provides similar functionality with an almost identical API. The go-sparkle package supports both Sparkle and WinSparkle, making it easy to support both platforms with minimal code changes.
+
+
+
+## Conclusion
+
+You've now successfully integrated Sparkle into your Wails application, providing a robust self-update mechanism for your users. This approach gives you complete control over the update process whilst providing a native experience for your users.
+
+For production use, you'll want to:
+
+1. Host your updates on a secure server with HTTPS
+2. Keep your private key secure
+3. Consider using a CI/CD pipeline to automate the build, signing, and appcast generation process
+
+## References
+
+:::note
+This tutorial is based on [Marcus Crane's](https://github.com/marcus-crane) [Wails Sparkle guide](https://github.com/marcus-crane/wails3-sparkle-poc)
+:::
+
+- [Sparkle Documentation](https://sparkle-project.org/documentation/)
+- [go-sparkle Repository](https://github.com/abemedia/go-sparkle)
+- [WinSparkle Documentation](https://github.com/vslavik/winsparkle/wiki)