# Troubleshooting

If you are having trouble integrating the SDK, uploading your certificates or sending notifications, here are some suggestions.

### Displaying a stable debug ID

The **Installation ID** is an ID generated by Batch for all the installs the first time your users open the app. You can safely display it in your app to simplify the debug process.

You can use that ID in the [debug tool](/developer/sdk/ios/profile-data/debug.md) (Dashboard settings > Debug) to find your own install, see the data Batch has on it and send test notifications to your device.

Your end users can also send it to you so you can understand why they are not receiving push notifications or not seeing an In-App message. This is useful when your app doesn't share any advertising ID with Batch.

![Debug iOS](/files/UUZLiapbGG3DF2rSTJwy)

You can also store the install ID on your end and reuse it later to target specific installs using the [Transactional API](/developer/api/mep/transactional.md).

#### Retrieving the installation ID

You can retrieve the installation ID by calling the following methods:

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

```swift
BatchUser.installationID()
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
[BatchUser installationID];
```

{% endtab %}
{% endtabs %}

#### Displaying the installation ID

That installation ID can be exposed to your end users. You can insert it in a diagnostic email automatically generated when users report an issue from the app or hide it in an easter egg.

![Example](/files/e5prh3YwRifUi64eyR6P)

#### Copying the installation ID

Batch will copy the installation ID to the clipboard when the application appears in the foreground 4 times within 20 seconds. This is **enabled** by default, you can disable it at any time by using:

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

```swift
class AppDelegate: UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // This can be called at any time, even before starting Batch.
        BatchSDK.setEnablesFindMyInstallation(false)
        // ...
    }
}
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // This can be called at any time, even before starting Batch.
    [BatchSDK setEnablesFindMyInstallation:false]
    // ...
}
```

{% endtab %}
{% endtabs %}

### Enabling internal logs

Internal logs can be useful to you or our support team to debug issues that might not be debuggable using public logs. They're disabled by default as they are very verbose by design.

They can be enabled in two ways:

#### Using code

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

```swift
class AppDelegate: UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // This can be called at any time, even before starting Batch.
        // Enabling logs as early as possible ensures that you don't miss important events.
        BatchSDK.setInternalLogsEnabled(true)
        // ...
    }
}
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // This can be called at any time, even before starting Batch.
    // Enabling logs as early as possible ensures that you don't miss important events.
    [BatchSDK setInternalLogsEnabled:true];
    // ...
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Please make sure that you do not enable internal logs on an App Store build.
{% endhint %}

#### Using a command line argument

Command line arguments are only usable when an app is launched by Xcode or while running tests. This is an easy way to make sure that logs never end up in a production build. However, they cannot be allow for internal logs to be read by testers.

Batch will enable internal logs if the app has been launched with `-BatchSDKEnableInternalLogs`:

![Adding the command line flag using Xcode's scheme editor](/files/Ij7j4ChA51UPN1InsAM1)

### Implementing Batch debugger

The debug view is a UI with multiple debug features, allowing you to see the **native** and **custom data** attached to your install. You can also see the **list of In-App campaigns** already stored in your device.

![Debugger overview](/files/DLsCUwCO2o69fNFtyHeZ)

This is useful for development purposes and for internal uses only, especially if your team cannot use an advertising or a custom user id to find their device in the debug tool and send test notifications to their device.

#### Identifiers

![Debugger native data](/files/Ar39jvpcadRnoZERbyhn)

Shows a list of native information you can use for basic debug:

* Batch SDK version
* Installation ID
* Advertising ID
* Push token
* APN Environment

You can easily share that report by clicking the share button in the top right corner.

#### Custom user data

![Debugger custom data](/files/h9nN55VB8hxclRvc951b)

Shows the custom user data attached to your install, excluding events. This is useful to:

* Check the Custom User ID attached to the install ([see more here](/developer/sdk/ios/profile-data/custom-user-id.md)).
* See the list of attributes / tag collections attached to your install. You can use that part to see if the app has been tagged correctly or understand why your device didn't receive a notification based on a one of these information.

#### In-App campaigns

![Debugger in-app](/files/PE0VBg1xrccsUX3QNjB1)

Use that part to manually pull the campaigns available on Batch servers for your install and to see the list of stored In-App campaigns.

#### Implementing the debugger

The debugger should be presented modally:

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

```swift
if let debugVC = BatchSDK.makeDebugViewController() {
    present(debugVC, animated: true, completion: nil)
}
```

{% endtab %}

{% tab title="Swift UI" %}

```swift
import SwiftUI
import Batch

struct BatchDebugView: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> some UIViewController {
        return BatchSDK.makeDebugViewController() ?? UIViewController()
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
    }
}

struct ContentView: View {
    @State var showBatchDebug = false
    
    var body: some View {
        VStack {
            Button("Open Batch Debug") {
                self.showBatchDebug = true
            }.sheet(isPresented: self.$showBatchDebug) {
                BatchDebugView()
            }
        }
    }
}
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
UIViewController *debugVC = [BatchSDK makeDebugViewController];
if (debugVC) {
    [self presentViewController:debugVC animated:YES completion:nil];
}
```

{% endtab %}
{% endtabs %}

You can hide it in an easter egg (e.g. display it after 10 taps on specific button, etc) or simply display it in your app settings for your development versions exclusively.

### Common issues

#### I’m not seeing any data on my dashboard

There are several points you should check if Batch doesn't show any data on your dashboard:

* **24h delay**. Installs, DAU, starts and redeems shown on the Analytics tab are updated on a 24h basis.
* **Integration issue**. If you still don't see any stats for your app 24h after changing the API key, see if you find anything related to Batch in your logs and double check your integration using the documentation.

#### "Unable to find a token"

There are several points you should check if Batch doesn't detect any device tokens:

* **Push disabled**: See if you have enabled the notifications for your app in the iOS settings *(Settings → Notifications)*.
* **Look for errors**: Check your Xcode logs to see if Batch published any error messages.
* **Provisioning issue**: Make sure you have correctly set up your provisioning profile with Xcode.

#### My device doesn't seem to receive any notifications

If you are not receiving any of the notifications sent from Batch, here are some suggestions to find the issue:

* **App opened**: Make sure your app is not opened in the foreground during your tests. By default iOS only displays notifications for apps opened in the background: It only calls your delegate, which can be invisible to you if you don't log anything.
* **Push disabled**: See if you have enabled the notifications for your app in iOS settings *(Settings → Notifications)*.
* **Connection issues**: Connect your device to a 3G/4G network or try to disconnect/reconnect to your WiFi network.
* **Test notifications**: Try to send a test notification to your device from the message editor *("Push" tab → "New push campaign" → "Send a test")*.

#### I'm receiving notifications twice

You may receive the same notification twice if you have reinstalled your app with different API keys, several times on the same device *(Dev/Live)*. Rest assured, your users won't receive the same notification twice.

### Certificates issues

#### The .p12 export button is greyed out

Make sure you have selected the *default login keychain* in the left pane of the Keychain application, and selected *"My certificates"* in the top filtering bar of the Keychain application.

#### "Wrong file or password"

First, double-check your certificate password. If your password is correct, make sure your certificate is not named *"Apple Production IOS Push Services"* or *"Apple Development IOS Push Services"*. These are not supported anymore. You will need to [generate a new production certificate](https://doc.batch.com/developer/sdk/ios/pages/LGYgNVUG2DhMZicjx5p6#generating-the-.p12-certificate) if it's the case.

#### "Unable to parse the p12"

You cannot upload Apple's certificate directly. You will find more information on certificate generation [here](https://doc.batch.com/developer/sdk/ios/pages/LGYgNVUG2DhMZicjx5p6#generating-the-.p12-certificate).

#### “Legacy or development certificates are no longer supported”

Development certificates or production certificates named *"Apple Production IOS Push Services"* are not supported anymore. Please generate a new [.p8 certificate](/developer/sdk/ios/prerequisites.md#configuring-notifications).

### Test push issues

#### "DeviceTokenNotForTopic"

*DeviceTokenNotForTopic* errors happen when your app's **bundle ID** and certificate's bundle ID don't match.

![Bundle ID](/files/FLHwdOD0m5hGtG7xTCe0)

Please ensure you set up your bundle ID correctly in your Xcode project settings.

#### "BadDeviceToken"

*BadDeviceToken* errors can happen for two reasons:

* **Invalid token**: On iOS 9 and higher, your device token may change if you uninstall/reinstall an app. Please make sure your token hasn't changed since your last tests. See how to obtain your token [here](broken://pages/7u41RcK8lsEezyrMnuyi).
* **Wrong environment**: If your device token is valid, make sure you have chosen the right environment *(sandbox/production)* from Batch settings *(Settings → Push settings)*. You can find the right environment for your token with our [debug tool](/developer/sdk/ios/profile-data/debug.md).

#### "The attempt to send a \[test] notification was rejected : invalid certificate"

If you see an *"Invalid certificate"* error, this means that:

* **Legacy certificates**: You are currently using a legacy certificate and the Development or the Production certificates are missing.
* **Delay**: Batch is still processing your certificates. Please try again in a few minutes and reach us if the problem persists.

#### "There was an unknown error while processing the request"

If you are getting an unknown error, please contact us at <support@batch.com> or by clicking on the question mark in the bottom right corner. Our team will try to find more details on the issue.

### APNS/internal errors

You can find the list of APNS and Batch internal errors in the [Notifications tab](https://doc.batch.com/getting-started/other/dashboard/01-analytics/04-notifications), by hovering on the error count.

#### apns\_invalid\_token

APNS can send this feedback when:

* **Invalid token**: The token Batch tries to push is not valid anymore. This usually happens when users uninstall/reinstall *(iOS 9.x and higer)* your app or disable notifications.
* **Wrong environment**: Make sure you are targeting the right environment *(sandbox/production)* for your token.

#### apns2\_device\_token\_not\_for\_topic

Happens when your app's **bundle ID** and certificate's bundle ID don't match. Make sure you set up your bundle ID correctly in your Xcode project settings.

#### apns2\_topic\_disallowed

Make sure the App ID/Bundle ID or the team ID you used for your P8 certificate are correct.

#### max\_retry\_attempts

This internal error happens when the number of maximum send attempts is reached for a token. Feel free to reach us if you are seeing to many max\_retry\_attemps errors.


---

# 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://doc.batch.com/developer/sdk/ios/troubleshooting.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.
