# Blocking Ads and Trackers

## Blocking Ads and Trackers on Android and JavaScript

Before checking if a URL is allowed, you should activate at least one ruleset and allow the Ad/Tracker Blocker to compile the rules.

### Filtering Status

The Ad/Tracker Blocker client can take some time to compile the rules after changing the active rulesets. Use the `status` property to determine the state of this process.

{% tabs %}
{% tab title="TypeScript" %}

```typescript
import { Status } from '@sudoplatform/sudo-ad-tracker-blocker'

/*
 * Status values:
 * 
 * Status.Preparing: 
 *   Calls to checkUrl() will be resolved when status 
 *   becomes `Ready`.
 *
 * Status.Ready:
 *   Filter engine is ready and calls to checkUrl()
 *   will be answered immediately.
 *
 * Status.Error:
 *   An error occured while (re) initializing the 
 *   filter engine.
 */

const status: Status = client.status
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
// val client: SudoAdTrackerBlockerClient

enum class FilterEngineStatus {
    /** The filter engine is (re)initializing */
    PREPARING,
    /** The filter engine is ready to be used */
    READY,
    /** The filter engine failed to update or initialize correctly */
    ERROR,
    UNKNOWN
}

/** The status of the filter engine. */
val status = client.status
```

{% endtab %}
{% endtabs %}

### Check URL Against Active Rulesets

To check if a URL should be blocked or allowed, call the `checkUrl` method and supply the URL in question. The input to the `checkUrl` function consists of two URLs. The first is the URL of a resource that is being requested, and the second is the URL of the main page, if any. If the main page URL is provided and is present in the list of exceptions, content will not be blocked.

If the MIME type of the requested URL is known, it can optionally be provided to aid blocking decisions.

{% tabs %}
{% tab title="TypeScript" %}

```typescript
const url = "http://somehost.com/somewhere/ad?type=banner"
const sourceUrl = "http://somehost.com/about-us"

const result: CheckUrlResult = await client.checkUrl(url, sourceUrl)
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
// val client: SudoAdTrackerBlockerClient

launch {
    try {
        if (client.status != SudoAdTrackerBlockerClient.FilterEngineStatus.READY) {
            return@launch
        }
        withContext(Dispatchers.IO) {
            val urlStatus = client.checkUrl(
                url = "http://somehost.com/somewhere/ad?type=banner",
                sourceUrl = "http://somehost.com/about-us"
            )
            if (urlStatus == SudoAdTrackerBlockerClient.CheckUrlResult.BLOCKED) {
                // URL should not be loaded
            }
        }
    } catch (e: SudoAdTrackerBlockerException) {
        // Handle/notify user of exception
    }
}
```

{% endtab %}
{% endtabs %}

## Blocking Ads and Trackers on iOS

The iOS SDK differs from other platforms due to the requirements of [Apple's Content Blocker implementation](https://developer.apple.com/documentation/safariservices/creating_a_content_blocker). Whereas the Android and JavaScript SDKs provide a custom blocking engine, the iOS SDK provides ruleset data in the Apple Content Blocking format. The lists provided by the iOS SDK can then be used to block content in [WKWebView](https://developer.apple.com/documentation/webkit/wkusercontentcontroller) or [the system Safari app](https://developer.apple.com/documentation/safariservices/creating_a_content_blocker).

### Fetching Content Blocker Data

Use the `getContentBlocker` function to retrieve ruleset data in the Apple Content Blocking format. The `rulesetData` property of the returned `ContentBlocker` can then be used with a `WKWebView` or the system Safari app. The ruleset data is a combination of the base ruleset data plus any exceptions added via the client. See [Manage Exceptions](/guides/ad-tracker-blocker/manage-exceptions.md) for documentation on adding/removing exceptions.

Ruleset data is cached for performance, and the most recent ruleset is always fetched if the cache is out of date.

{% tabs %}
{% tab title="Swift" %}

```swift
do {
    let contentBlocker = try await client.getContentBlocker(ruleset: ruleset)
} catch {
    // Handle failure
}

/// Represents a base ruleset combined with a list of exceptions.
public struct ContentBlocker {

    /// Generated ID of this content blocker. Based on the base ruleset and an exceptions added.
    public let id: String

    /// The base ruleset used to generate the content blocking json
    public let baseRuleset: Ruleset

    /// The content blocking json in Apples content blocking format.  This can be passed to either a content blocking extension or Webkit for blocking.
    public let rulesetData: String

    /// Exceptions applied to the content blocker.
    public let exceptions: [BlockingException]
}
```

{% endtab %}
{% endtabs %}

The `getRuleset` function can be used to retrieve the base ruleset data without any exceptions applied.

### Using Ruleset Data with a WKWebView

The `rulesetData` from the iOS SDK can be used to block content in a WebKit View. Refer to Apple's documentation on [WKContentRuleList](https://developer.apple.com/documentation/webkit/wkcontentrulelist) and [WKUserContentController](https://developer.apple.com/documentation/webkit/wkusercontentcontroller) for more details.

{% hint style="info" %}
Compiling a ruleset can be an expensive operation. The `id` property of a `ContentBlocker` can be used as a cache key to avoid unnecessary compilation.
{% endhint %}

{% tabs %}
{% tab title="Swift" %}

```swift
let contentBlocker: ContentBlocker // ... see above ...

let store = WKContentRuleListStore.default()
store.compileContentRuleList(
    forIdentifier: contentBlocker.id,
    encodedContentRuleList: contentBlocker.rulesetData
) { (ruleList, error) in
    guard let ruleList = ruleList else {
        // Display or log the error.
        return
    }

    let userContentController = WKUserContentController()
    userContentController.add(ruleList)

    let configuration = WKWebViewConfiguration()
    configuration.userContentController = userContentController
    let webView = WKWebView(frame: .zero, configuration: configuration)
    // Present the web view.
}
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.sudoplatform.com/guides/ad-tracker-blocker/blocking-ads-and-trackers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
