---
title: "TN3102: HTTP/3 in your app"
framework: technotes
role: article
role_heading: Article
path: technotes/tn3102-http3-in-your-app
---

# TN3102: HTTP/3 in your app

Get started with iOS 15’s new HTTP/3 support.

## Overview

Overview HTTP/3 is a major new feature in iOS 15. While you wait for your server to add support for it, here’s how you can test it today in your app: Make sure your test device is running iOS 15 or later (HTTP/3 is not supported in the simulator). In Settings > Developer, under the Networking group, enable HTTP/3. Using Xcode 13.0 or later, create a new project from the iOS > App template. Set the Language popup to Swift and the Interface popup to SwiftUI. Change the HTTP3App.swift and the ContentView.swift files to the code shown below. Run the app on your device. Tap your Test button.

// HTTP3App.swift

@main struct HTTP3App: App {     let networkManager = NetworkManager()     var body: some Scene {         WindowGroup {             ContentView(networkManager: networkManager)         }     } }

// ContentView.swift

import SwiftUI import os.log

struct ContentView: View {     var networkManager: NetworkManager          var body: some View {         VStack(alignment: .leading) {             Button("Test HTTP3") {                 networkManager.testHTTP3Request()             }.padding(.vertical, 20)         }.padding(40)     } }

struct ContentView_Previews: PreviewProvider {     static var previews: some View {         ContentView()     } }

class NetworkManager: NSObject, URLSessionDataDelegate {          private var session: URLSession!          func testHTTP3Request() {                  if self.session == nil {             let config = URLSessionConfiguration.default             config.requestCachePolicy = .reloadIgnoringLocalCacheData             self.session = URLSession(configuration: config, delegate: self, delegateQueue: .main)         }                  let urlStr = "https://google.com"         let url = URL(string: urlStr)!         var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 60.0)         request.assumesHTTP3Capable = true         os_log("task will start, url: \(url.absoluteString)")         self.session.dataTask(with: request) { (data, response, error) in             if let error = error as NSError? {                 os_log("task transport error \(error.domain) / \(error.code)")                 return             }             guard let data = data, let response = response as? HTTPURLResponse else {                 os_log("task response is invalid")                 return             }

guard 200 ..< 300 ~= response.statusCode else {                 print("task response status code is invalid; received \(response.statusCode), but expected 2xx")                 return             }             os_log("task finished with status \(response.statusCode), bytes \(data.count)")         }.resume()              } }

extension NetworkManager {          func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) {         let protocols = metrics.transactionMetrics.map { $0.networkProtocolName ?? "-" }         os_log("protocols: \(protocols)")     } } Testing notes After running the code above, your app will print something similar to: task will start, url: <# Your H3 URL Here #> protocols: ["h3-29"] // ["h3", "h2"] task finished with status 200, bytes 703 The protocols array shows the protocol used for each HTTP transaction. In this case there was a single HTTP/3 transaction. In some cases you may see the protocol being returned as h2 or even http1.1. If this is the case then run the transaction again. This gives URLSession the opportunity to apply the HTTP/3 service discovery option that your server sent back on the previous HTTP response. Service discovery for HTTP/3 is performed in one of the following ways: The recommended approach is to configure your DNS server to advertise the HTTPS resource record for alpn="h3,h2". Alternatively, configure your server to respond back with the Alt-Svc header that advertises HTTP/3. For example, Alt-Srv: h3=":443"; ma=2592000. To attempt to use HTTP/3 on the first transaction, set the assumesHTTP3Capable property on the URLRequest being used to execute the data task in URLSession. For cases where HTTP/3 is not supported on the server, or over the network, you will see the protocol fall back to h2 or http1.1. For more information on this, please see the WWDC session for Accelerate networking with HTTP/3 and QUIC. note: Servers that support HTTP/3 need to be based on Draft 29 or later. If you experience issues while debugging your network transactions, take a look at these requests in the Network Instruments tool to debug what you are seeing being sent back from your server. For more on this, see the article for Analyzing HTTP Traffic with Instruments. Revision History 2022-05-24 Made minor editorial changes. 2022-02-08 Republished as TN3102. 2021-06-16 First published as “HTTP/3 in Your App” on the Apple Developer Forums.

## See Also

### Latest

- [TN3210: Optimizing your app for iPhone Mirroring](technotes/tn3210-optimizing-your-app-for-iphone-mirroring.md)
- [TN3211: Resolving SwiftUI source incompatibilities for State and ContentBuilder](technotes/tn3211-resolving-swiftui-source-incompatibilities-for-state-and-contentbuilder.md)
- [TN3212: Adopting gesture recognizers for Sidecar touch support](technotes/tn3212-adopting-gesture-recognizers-for-sidecar-touch-support.md)
- [TN3208: Preparing your app’s launch screen to meet App Store requirements](technotes/tn3208-preparing-your-apps-launch-screen-to-meet-app-store-requirements.md)
- [TN3205: Low-latency communication with RDMA over Thunderbolt](technotes/tn3205-low-latency-communication-with-rdma-over-thunderbolt.md)
- [TN3206: Updating Apple Pay certificates](technotes/tn3206-updating-apple-pay-certificates.md)
- [TN3179: Understanding local network privacy](technotes/tn3179-understanding-local-network-privacy.md)
- [TN3190: USB audio device design considerations](technotes/tn3190-usb-audio-device-design-considerations.md)
- [TN3194: Handling account deletions and revoking tokens for Sign in with Apple](technotes/tn3194-handling-account-deletions-and-revoking-tokens-for-sign-in-with-apple.md)
- [TN3193: Managing the on-device foundation model’s context window](technotes/tn3193-managing-the-on-device-foundation-model-s-context-window.md)
- [TN3115: Bluetooth State Restoration app relaunch rules](technotes/tn3115-bluetooth-state-restoration-app-relaunch-rules.md)
- [TN3192: Migrating your iPad app from the deprecated UIRequiresFullScreen key](technotes/tn3192-migrating-your-app-from-the-deprecated-uirequiresfullscreen-key.md)
- [TN3151: Choosing the right networking API](technotes/tn3151-choosing-the-right-networking-api.md)
- [TN3111: iOS Wi-Fi API overview](technotes/tn3111-ios-wifi-api-overview.md)
- [TN3191: IMAP extensions supported by Mail for iOS, iPadOS, and visionOS](technotes/tn3191-imap-extensions-supported-by-mail.md)
