TLDExtract

August 21, 2026 · View on GitHub

Swift Package Manager compatible Carthage Swift Package Index Platforms Build codecov License

TLDExtract

TLDExtract is a pure Swift library to allows you to get the public suffix of a domain name using the Public Suffix List. You can find alternatives for other languages at publicsuffix.org.

What are domains?

Domain names are the unique, human-readable Internet addresses of websites. They are made up of three parts: a top-level domain (a.k.a. TLD), a second-level domain name, and an optional subdomain.

drawing

Changes in 3.0.0

Breaking changes

  • ‼️ Library name changed from TLDExtract to TLDExtractSwift to resolve namespace conflicts. For more details, please check the issue (apple/swift#56573).

    Please don't forget to update your source code.

    - import TLDExtract
    + import TLDExtractSwift
    

Other changes

  • Dropped support for Swift 4.
  • Added watchOS and visionOS to supported platforms.
  • Changed supported versions for macOS, iOS, and tvOS to match Xcode 15.4.

Feature

  • Extract root domain, top level domain, second level domain, subdomain from url and hostname
  • Foundation URL and String support
  • IDNA support
  • Multi platform support

Requirements

  • macOS 10.13 or later
  • iOS 12.0 or later
  • tvOS 12.0 or later
  • watchOS 4.0 or later
  • visionOS 1.0 or later
  • Linux (SPM builds)
  • Swift 5.9 or later (Xcode 15 or later) for Swift Package Manager

Installation

Swift Package Manager is the recommended way to install TLDExtractSwift.

Important

CocoaPods distribution has ended: 3.0.0 is the last version published as a pod. Future versions are available via Swift Package Manager (and Carthage on a best-effort basis) only. If you are using CocoaPods, please migrate to Swift Package Manager.

Swift Package Manager

Add the following to your Package.swift file.

  • macOS, iOS, tvOS, watchOS, visionOS, Linux, and Swift 5.9 (Xcode 15) or later

    dependencies: [
        .package(url: "https://github.com/futamura/TLDExtractSwift.git", .upToNextMajor(from: "4.0.0"))
    ]
    
  • macOS, iOS, tvOS, watchOS, visionOS, and Swift 5

    dependencies: [
        .package(url: "https://github.com/futamura/TLDExtractSwift.git", .upToNextMajor(from: "3.0.0"))
    ]
    
  • macOS, iOS, tvOS, and Swift 5

    dependencies: [
        .package(url: "https://github.com/futamura/TLDExtractSwift.git", .upToNextMajor(from: "2.1.1"))
    ]
    

Carthage

Note

Carthage itself is in maintenance mode. Carthage compatibility is kept on a best-effort basis and is no longer verified by CI.

Add the following to your Cartfile and follow these instructions.

  • macOS, iOS, tvOS, watchOS, visionOS, and Swift 5.9 or later

    github "futamura/TLDExtractSwift" ~> 4.0
    
  • macOS, iOS, tvOS, watchOS, visionOS, and Swift 5

    github "futamura/TLDExtractSwift" ~> 3.0
    
  • macOS, iOS, tvOS, and Swift 5

    github "futamura/TLDExtractSwift" ~> 2.0
    
  • macOS, iOS, tvOS, and Swift 4

    github "futamura/TLDExtractSwift" ~> 1.0
    

Do not forget to include Punycode.framework. Otherwise it will fail to build the application.

drawing

CocoaPods

Warning

CocoaPods distribution has ended: 3.0.0 is the last version published as a pod. Existing versions remain installable until the trunk archive disappears, but no new versions will be published. Please migrate to Swift Package Manager.

Existing installations reference the pod as follows.

  • macOS, iOS, tvOS, watchOS, visionOS, and Swift 5.0

    pod 'TLDExtractSwift', '~> 3.0'
    
  • macOS, iOS, tvOS, and Swift 5.0

    pod 'TLDExtract', '~> 2.0'
    
  • macOS, iOS, tvOS, and Swift 4.2

    pod 'TLDExtract', '~> 1.0'
    

Usage

Full documentation is available at https://futamura.github.io/TLDExtractSwift/documentation/tldextractswift/.

Initialization

Basic initialization code. Exceptions will not be raised unless the Public Suffix List on the server is broken.

import TLDExtractSwift

let extractor = try! TLDExtract()

A safer initialization code to avoid errors by using the frozen Public Suffix List:

import TLDExtractSwift

let extractor = try! TLDExtract(useFrozenData: true)

*In SPM builds the default initializer downloads the live Public Suffix List; setting useFrozenData to true uses the bundled snapshot instead. Framework builds always use the bundled list, which is regenerated with python update-psl.py.

Extraction

Passing argument as String

Extract an url:

let urlString: String = "https://www.github.com/futamura/TLDExtract"
guard let result: TLDResult = extractor.parse(urlString) else { return }

print(result.rootDomain)        // Optional("github.com")
print(result.topLevelDomain)    // Optional("com")
print(result.secondLevelDomain) // Optional("github")
print(result.subDomain)         // Optional("www")

Extract a hostname:

let hostname: String = "futamura.dev"
guard let result: TLDResult = extractor.parse(hostname) else { return }

print(result.rootDomain)        // Optional("futamura.dev")
print(result.topLevelDomain)    // Optional("dev")
print(result.secondLevelDomain) // Optional("futamura")
print(result.subDomain)         // nil

Extract an unicode hostname:

let hostname: String = "www.ラーメン.寿司.co.jp"
guard let result: TLDResult = extractor.parse(hostname) else { return }

print(result.rootDomain)        // Optional("寿司.co.jp")
print(result.topLevelDomain)    // Optional("co.jp")
print(result.secondLevelDomain) // Optional("寿司")
print(result.subDomain)         // Optional("www.ラーメン")

Extract a punycoded hostname (Same as above):

let hostname: String = "www.xn--4dkp5a8a.xn--sprr0q.co.jp")"
guard let result: TLDResult = extractor.parse(hostname) else { return }

print(result.rootDomain)        // Optional("xn--sprr0q.co.jp")
print(result.topLevelDomain)    // Optional("co.jp")
print(result.secondLevelDomain) // Optional("xn--sprr0q")
print(result.subDomain)         // Optional("www.xn--4dkp5a8a")

Passing argument as Foundation URL

Extract an unicode url:
URL class in Foundation Framework does not support unicode URLs by default. You can use URL extension as a workaround

let urlString: String = "http://www.ラーメン.寿司.co.jp"
let url: URL = URL(unicodeString: urlString)
guard let result: TLDResult = extractor.parse(url) else { return }

print(result.rootDomain)        // Optional("www.ラーメン.寿司.co.jp")
print(result.topLevelDomain)    // Optional("co.jp")
print(result.secondLevelDomain) // Optional("寿司")
print(result.subDomain)         // Optional("www.ラーメン")

Encode an url by passing argument as percent encoded string (Same as above):

let urlString: String = "http://www.ラーメン.寿司.co.jp".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
let url: URL = URL(string: urlString)
print(urlString)                // http://www.%E3%83%A9%E3%83%BC%E3%83%A1%E3%83%B3.%E5%AF%BF%E5%8F%B8.co.jp

guard let result: TLDResult = extractor.parse(url) else { return }

print(result.rootDomain)        // Optional("www.ラーメン.寿司.co.jp")
print(result.topLevelDomain)    // Optional("co.jp")
print(result.secondLevelDomain) // Optional("寿司")
print(result.subDomain)         // Optional("www.ラーメン")

Encode a unicode url by using the Punycode Framework. idnaEncodedURL (PunycodeSwift 4.0 or later) encodes the host component only, preserving the scheme and the rest of the URL — idnaEncoded is the hostname-level equivalent and must not be applied to a full URL:

import Punycode

let urlString: String = "http://www.ラーメン.寿司.co.jp".idnaEncodedURL!
let url: URL = URL(string: urlString)!
print(urlString)                // http://www.xn--4dkp5a8a.xn--sprr0q.co.jp

guard let result: TLDResult = extractor.parse(url) else { return }

print(result.rootDomain)        // Optional("xn--sprr0q.co.jp")
print(result.topLevelDomain)    // Optional("co.jp")
print(result.secondLevelDomain) // Optional("xn--sprr0q")
print(result.subDomain)         // Optional("www.xn--4dkp5a8a")

TLDExtract is released under MIT license, which means you can modify it, redistribute it or use it however you like.