๐Ÿ“ฑ iOS

An example integration can be found in the Example App.

Getting Started


Request access by emailing [email protected].

To add the package to your app, in Xcode, go to File > Swift Packages > Add Package Dependency and enter this repository url (https://github.com/sgoodbets/sharpsports-spm), or type sharpsports-spm in the search bar.

Decide on your Package Requirements and close the window.

For more information, check out Adding Package Dependencies to Your App.

Check the Example folder to see how to integrate the framework into your app.


Mobile Auth Token

To initialize the framework, first fetch the mobile auth token.

Task.detached(priority: .background) { @MainActor in
    do {
        let mobileAuthToken = try await self.mobileAuthService.getMobileAuthToken()
        let sharpSportsMobile = SharpSportsMobile.shared
        let keys = SharpSportsMobile.Keys(
            publicKey: "a4e27d45042947e7967146c26973bbd4a4e27d45",
            mobileAuthToken: mobileAuthToken.token,
            internalId: "dd-test-ios"
        sharpSportsMobile.setKeys(keys: keys)
    } catch {
        print("fetching mobile auth token failed with error: \(error)")

Fetch Context

Next, call the context method to retrieve a cid to load into your WebView instance.

SharpSportsMobile.shared.context { result in
    DispatchQueue.main.async { [weak self] in
        guard let self = self else { return }
        switch result {
        case .success(let cid):
            // build the url you want to host here
        case .failure(let error):
            print("error fetching context: \(error)")

The completion handler will pass back the cid which you can use to load the SharpSports UI in your webview.

let url = URL(string: "https://ui.sharpsports.io/link/\(response.cid)")!

Before loading the url into your webview, make sure to add our custom scripts for fetching bets.
This will make sure your integration works for all sportsbooks.

let configuration = WKWebViewConfiguration()
self.sharpSportsMobile.addScripts(configuration: configuration)
let webView = WKWebView(frame: .zero, configuration: configuration)

Also, make sure to call through to the SharpSports navigation handler:

// MARK: - WKNavigationDelegate
extension ViewController: WKNavigationDelegate {
    public func webView(
        _ webView: WKWebView,
        decidePolicyFor navigationAction: WKNavigationAction,
        decisionHandler: @escaping (WKNavigationActionPolicy) -> Void
    ) {
        sharpSportsMobile.onNavigationStateChange(webView, decidePolicyFor: navigationAction, decisionHandler: decisionHandler)

Next, conform to the SharpSportsMobileDelegate methods:

public protocol SharpSportsMobileDelegate: class {
  /// Called when the API request to the backend is initiated.
  /// Use this in order to display any loading indicator UI you want to the user.
  func webViewWillLoad()
  /// Called when the API request to the backend has finished.
  /// Use this in order to dismiss any loading indicator UI you've previously displayed.
  func webViewDidFinishLoading()
  /// Called when the webview has loaded the portal.
  /// Use this in order to display the SharpSports portal in your app.
  /// - Parameter viewController: the viewController hosting the SharpSports web portal.
  func present(viewController: UIViewController)

  /// Called when the portal is closed, by interacting with the Continue button.
  func dismissWebView()
  /// Called when bettor verification is successful
  func verificationDidFinishSuccesfully()
  /// Called when the API request to the SharpSports backend fails.
  /// - Parameter error: the reason for the failure.
  func linkingSportsbookFailed(with error: SharpSportsMobileError)

All methods are required, but the methods that you can use to control displaying / dismissing are:

func present(viewController: UIViewController)
func dismissWebView()

These methods will inform you when to display and dismiss the contents of the login portal.

Styling your button

The SharpSportsButtonOptions struct is used to style the button according to how you want it to look.

public struct SharpSportsButtonOptions {
  let buttonText: String
  let backgroundColor: UIColor
  let buttonColor: UIColor
  let cornerRadius: CGFloat
  let fontFamily: String
  let fontSize: CGFloat
  let edgeInsets: UIEdgeInsets
  public init(buttonText: String = "SharpSports",
              backgroundColor: UIColor = .blue,
              buttonColor: UIColor = .white,
              cornerRadius: CGFloat = 5,
              fontFamily: String = "Helvetica",
              fontSize: CGFloat = 20,
              edgeInsets: UIEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)) {
    self.buttonText = buttonText
    self.backgroundColor = backgroundColor
    self.buttonColor = buttonColor
    self.cornerRadius = cornerRadius
    self.fontFamily = fontFamily
    self.fontSize = fontSize
    self.edgeInsets = edgeInsets


The Refresh method will allow you to make refresh requests to the SharpSports API.


By default the Refresh method will run a refresh on all accounts associated with the internalId that you provided when initializing the SharpSportsMobile object. Optionally you can pass a bettorId to refresh all accounts associated with that ID or a bettorAccountId to refresh just a specific account.

You can also optionally pass reverify: true as an argument to attach the reverify query parameter to the refresh request.

bettorId: String?
bettorAccountId: String?
reverify: Bool


Refresh by InternalID


corresponds to the API call

POST https://api.sharpsports.io/v1/bettors/<internalID>/refresh

Refresh by BettorID

sharpSportsMobile.refresh(refreshOption: .bettorId("BTTR_ID"))

corresponds to the API call

POST https://api.sharpsports.io/v1/bettors/<BTTR_ID>/refresh

Refresh by BettorAccountID

sharpSportsMobile.refresh(refreshOption: .bettorAccountId("BACT_ID"))

corresponds to the API call

POST https://api.sharpsports.io/v1/bettorAccounts/<BACT_ID>/refresh


sharpSportsMobile.refresh(.bettorAccountId("BACT_ID"), reverify: true)

corresponds to the API call

POST https://api.sharpsports.io/v1/bettorAccounts/<BACT_ID>/refresh?reverify=true