---
title: "Set up Apple and Game Center"
description: "Configure Apple services and sign players in on supported targets."
seo:
  noindex: true
---

{/* Copyright (c) 2026 Betide Studio. All Rights Reserved. */}

Use **Game Center** for Apple's achievements and leaderboards. Use **Sign In with Apple** when you need an Apple identity token for your backend or EOS Connect. They are separate sign-ins.

## Set up the app

Match your packaged app's bundle ID to its App Store Connect record and provisioning profile. Enable Game Center for the app and configure its achievements and leaderboards in [App Store Connect](https://developer.apple.com/help/app-store-connect/configure-game-center/overview-of-game-center). Enable the [Sign in with Apple capability](https://developer.apple.com/documentation/xcode/configuring-sign-in-with-apple) if you use Apple ID login.

In **Project Settings → Betide → Crossplay**, the Game Center settings control automatic authentication and the access point. **Auto Authenticate On Launch** is enabled by default; turn it off if your game starts login manually. Test in a signed **iOS or macOS** build.

## Authenticate with Game Center

**Blueprint**

<BlueprintViewer title="Game Center login" src="/blueprints/crossplay-apple-game-center-login.txt" />

**C++**

Game module dependencies: `GameCenterKit`, `BetideCore`, `Engine`.

```cpp
#include "Engine/GameInstance.h"
#include "Nodes/Auth/GCIK_Authentication.h"

DEFINE_LOG_CATEGORY_STATIC(LogGameAppleLogin, Log, All);

void SignInGameCenter(UGameInstance &GameInstance)
{
    auto *Login = UGCIK_Authenticate::Authenticate(&GameInstance);
    if (!Login)
        return;
    const TWeakObjectPtr<UGameInstance> WeakGameInstance(&GameInstance);
    Login->OnSuccessCallback = [WeakGameInstance](const FGCIK_LocalPlayer &Player,
                                                  const FBetideError &) {
        if (WeakGameInstance.IsValid())
            UE_LOG(LogGameAppleLogin, Log, TEXT("Signed in: %s"), *Player.DisplayName);
    };
    Login->OnFailureCallback = [WeakGameInstance](const FGCIK_LocalPlayer &,
                                                  const FBetideError &Error) {
        if (WeakGameInstance.IsValid())
            UE_LOG(LogGameAppleLogin, Warning, TEXT("%s"), *Error.GetLogString());
    };
    Login->Activate();
}
```

Use **Is Authenticated** for a check without prompting. Respect **Is Multiplayer Restricted** before offering multiplayer. In C++, both are on `UGCIK_AuthenticationLibrary` in the same header.

## Get an Apple identity token

**Blueprint**

<Accordion>
  <AccordionItem title="Get an Apple identity token">
<BlueprintViewer title="Get an Apple identity token" src="/blueprints/crossplay-apple-id-token.txt" />
  </AccordionItem>
  <AccordionItem title="Check stored Apple credentials">
<BlueprintViewer title="Check stored Apple credentials" src="/blueprints/crossplay-apple-credential-state.txt" />
  </AccordionItem>
</Accordion>

**C++**

```cpp
#include "Nodes/AppleSignIn/GCIK_AppleSignInNodes.h"

void RequestAppleToken(
    UObject *WorldContext,
    TFunction<void(const FGCIK_AppleSignInResult &, const FBetideError &)> Completion)
{
    auto *Login = UGCIK_AppleSignIn::SignInWithApple(WorldContext, {});
    if (!Login)
        return;
    Login->OnSuccessCallback = [Completion](const FGCIK_AppleSignInResult &Result,
                                            const FBetideError &Error) {
        UGCIK_AppleSignInLibrary::StoreAppleUserIdentifier(Result.UserIdentifier);
        if (Completion)
            Completion(Result, Error);
    };
    Login->OnFailureCallback = MoveTemp(Completion);
    Login->Activate();
}
```

The completion receives `IdentityToken`. Use a weak UObject capture if it updates game objects.

<Accordion>
  <AccordionItem title="Check stored Apple credentials">

Add these methods to your GameInstance class. The node reports through dynamic delegates.

```cpp
#pragma once
#include "Engine/GameInstance.h"
#include "GameCenterKit.h"
#include "Nodes/AppleSignIn/GCIK_AppleSignInNodes.h"
#include "AppleSignInGameInstance.generated.h"

UCLASS()
class UAppleSignInGameInstance : public UGameInstance
{
    GENERATED_BODY()
  public:
    void CheckAppleCredentials()
    {
        auto *Check = UGCIK_GetAppleCredentialState::GetAppleCredentialState(
            this, UGCIK_AppleSignInLibrary::GetStoredAppleUserIdentifier());
        if (!Check)
            return;
        Check->OnComplete.AddDynamic(this, &UAppleSignInGameInstance::OnAppleCredentials);
        Check->OnFailure.AddDynamic(this, &UAppleSignInGameInstance::OnAppleCredentials);
        Check->Activate();
    }

    UFUNCTION()
    void OnAppleCredentials(EGCIK_AppleCredentialState State, const FBetideError &Error)
    {
        if (Error.IsError())
            UE_LOG(LogGCIK, Warning, TEXT("%s"), *Error.GetLogString());
        else
            UE_LOG(LogGCIK, Log, TEXT("Apple credential state: %d"), static_cast<int32>(State));
    }
};
```

  </AccordionItem>
</Accordion>

Pass the token explicitly to your chosen external-auth login. For automatic provider composition, use [Login With Crossplay](/crossplay/identity). Never log tokens.

Apple returns requested name/email information only on the first authorization; store it then if needed. Email can be a private relay address. Keep the returned user identifier for credential-state checks; clearing a locally stored identifier does not revoke Apple authorization.

Next: [Game Center services](/integrations/apple/game-services).
