---
title: Hooks
description: Handle user actions for logging, analytics, or side effects using the Handle Event Hook.
sidebar:
  order: 30
---

## Overview

Hooks are a way to trigger custom logic when certain actions happen in the authentication process.


<UITypeSwitch />

---

## Handle event hook


<VariantContent storageKey="ui-type" value="prebuilt">

Each frontend recipe emits events when certain actions happen.
You can use this hook to trigger side effects when something happens in the authentication process.
This can address things like logging or analytics.

<CodeGroup group="frontend-prebuilt-ui">
<Tab title="Reactjs" value="reactjs">
```tsx
import ThirdParty from "supertokens-auth-react/recipe/thirdparty";
import EmailPassword from "supertokens-auth-react/recipe/emailpassword";

EmailPassword.init({
  onHandleEvent: (context) => {
    if (context.action === "PASSWORD_RESET_SUCCESSFUL") {
    } else if (context.action === "RESET_PASSWORD_EMAIL_SENT") {
    } else if (context.action === "SUCCESS") {
      if (context.createdNewSession) {
        let user = context.user;
        if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
          // sign up success
        } else {
          // sign in success
        }
      } else {
        // during step up or second factor auth with email password
      }
    }
  },
});

ThirdParty.init({
  onHandleEvent: (context) => {
    if (context.action === "SUCCESS") {
      if (context.createdNewSession) {
        let user = context.user;
        if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
          // sign up success
        } else {
          // sign in success
        }
      } else {
        // during linking a social account to an existing account
      }
    }
  },
});
```
</Tab>
<Tab title="Angular" value="angular">
```tsx check=false reason="pre-built UI globals are provided by the host framework"
// this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded)

supertokensUIEmailPassword.init({
  onHandleEvent: (context) => {
    if (context.action === "PASSWORD_RESET_SUCCESSFUL") {
    } else if (context.action === "RESET_PASSWORD_EMAIL_SENT") {
    } else if (context.action === "SUCCESS") {
      if (context.createdNewSession) {
        let user = context.user;
        if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
          // sign up success
        } else {
          // sign in success
        }
      } else {
        // during step up or second factor auth with email password
      }
    }
  },
});

supertokensUIThirdParty.init({
  onHandleEvent: (context) => {
    if (context.action === "SUCCESS") {
      if (context.createdNewSession) {
        let user = context.user;
        if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
          // sign up success
        } else {
          // sign in success
        }
      } else {
        // during linking a social account to an existing account
      }
    }
  },
});
```
</Tab>
</CodeGroup>

</VariantContent>

<VariantContent storageKey="ui-type" value="custom">

:::warning[Not applicable since you need to build custom UI anyway.]
When you call the functions from the SDK, or call the API directly, you can run custom logic in your own code.
:::

</VariantContent>

---

## Pre-API hook

This function calls the backend before any API call.
You can use this to change the request properties.


<VariantContent storageKey="ui-type" value="prebuilt">

<CodeGroup group="frontend-prebuilt-ui">
<Tab title="Reactjs" value="reactjs">
```tsx
import ThirdParty from "supertokens-auth-react/recipe/thirdparty";
import EmailPassword from "supertokens-auth-react/recipe/emailpassword";

ThirdParty.init({
  preAPIHook: async (context) => {
    let url = context.url;
    let requestInit = context.requestInit;

    let action = context.action;
    if (action === "GET_AUTHORISATION_URL") {
    } else if (action === "THIRD_PARTY_SIGN_IN_UP") {
      // Note: this could either be sign in or sign up.
      // we don't know that at the time of the API call
      // since all we have is the authorisation code from
      // the social provider
    }

    // events such as sign out are in the
    // session recipe pre API hook (See the info box below)

    return {
      requestInit,
      url,
    };
  },
});

EmailPassword.init({
  preAPIHook: async (context) => {
    let url = context.url;
    let requestInit = context.requestInit;

    let action = context.action;
    if (action === "EMAIL_EXISTS") {
    } else if (action === "EMAIL_PASSWORD_SIGN_IN") {
    } else if (action === "EMAIL_PASSWORD_SIGN_UP") {
    } else if (action === "SEND_RESET_PASSWORD_EMAIL") {
    } else if (action === "SUBMIT_NEW_PASSWORD") {
    }

    // events such as sign out are in the
    // session recipe pre API hook (See the info box below)

    return {
      requestInit,
      url,
    };
  },
});
```
</Tab>
<Tab title="Angular" value="angular">
```tsx check=false reason="pre-built UI globals are provided by the host framework"
// this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded)

supertokensUIThirdParty.init({
  preAPIHook: async (context) => {
    let url = context.url;
    let requestInit = context.requestInit;

    let action = context.action;
    if (action === "GET_AUTHORISATION_URL") {
    } else if (action === "THIRD_PARTY_SIGN_IN_UP") {
      // Note: this could either be sign in or sign up.
      // we don't know that at the time of the API call
      // since all we have is the authorisation code from
      // the social provider
    }

    // events such as sign out are in the
    // session recipe pre API hook (See the info box below)

    return {
      requestInit,
      url,
    };
  },
});

supertokensUIEmailPassword.init({
  preAPIHook: async (context) => {
    let url = context.url;
    let requestInit = context.requestInit;

    let action = context.action;
    if (action === "EMAIL_EXISTS") {
    } else if (action === "EMAIL_PASSWORD_SIGN_IN") {
    } else if (action === "EMAIL_PASSWORD_SIGN_UP") {
    } else if (action === "SEND_RESET_PASSWORD_EMAIL") {
    } else if (action === "SUBMIT_NEW_PASSWORD") {
    }

    // events such as sign out are in the
    // session recipe pre API hook (See the info box below)

    return {
      requestInit,
      url,
    };
  },
});
```
</Tab>
</CodeGroup>

</VariantContent>

<VariantContent storageKey="ui-type" value="custom">



<CodeGroup group="frontend-custom-ui">
<Tab title="Web" value="web">
<DependentContent group="install-method" label="Installation method">
<ContentOption title="npm" value="npm">
```tsx
import ThirdParty from "supertokens-web-js/recipe/thirdparty";
import EmailPassword from "supertokens-web-js/recipe/emailpassword";

EmailPassword.init({
  preAPIHook: async (context) => {
    let url = context.url;
    let requestInit = context.requestInit;

    let action = context.action;
    if (action === "EMAIL_EXISTS") {
    } else if (action === "EMAIL_PASSWORD_SIGN_IN") {
    } else if (action === "EMAIL_PASSWORD_SIGN_UP") {
    } else if (action === "SEND_RESET_PASSWORD_EMAIL") {
    } else if (action === "SUBMIT_NEW_PASSWORD") {
    }

    // events such as sign out are in the
    // session recipe pre API hook (See the info box below)

    return {
      requestInit,
      url,
    };
  },
});

ThirdParty.init({
  preAPIHook: async (context) => {
    let url = context.url;
    let requestInit = context.requestInit;

    let action = context.action;
    if (action === "GET_AUTHORISATION_URL") {
    } else if (action === "THIRD_PARTY_SIGN_IN_UP") {
      // Note: this could either be sign in or sign up.
      // we don't know that at the time of the API call
      // since all we have is the authorisation code from
      // the social provider
    }

    // events such as sign out are in the
    // session recipe pre API hook (See the info box below)

    return {
      requestInit,
      url,
    };
  },
});
```
</ContentOption>
<ContentOption title="Script tag" value="script-tag">
```tsx check=false reason="script-tag installation provides SuperTokens globals at runtime"
supertokensEmailPassword.init({
  preAPIHook: async (context) => {
    let url = context.url;
    let requestInit = context.requestInit;

    let action = context.action;
    if (action === "EMAIL_EXISTS") {
    } else if (action === "EMAIL_PASSWORD_SIGN_IN") {
    } else if (action === "EMAIL_PASSWORD_SIGN_UP") {
    } else if (action === "SEND_RESET_PASSWORD_EMAIL") {
    } else if (action === "SUBMIT_NEW_PASSWORD") {
    }

    // events such as sign out are in the
    // session recipe pre API hook (See the info box below)

    return {
      requestInit,
      url,
    };
  },
});

supertokensThirdParty.init({
  preAPIHook: async (context) => {
    let url = context.url;
    let requestInit = context.requestInit;

    let action = context.action;
    if (action === "GET_AUTHORISATION_URL") {
    } else if (action === "THIRD_PARTY_SIGN_IN_UP") {
      // Note: this could either be sign in or sign up.
      // we don't know that at the time of the API call
      // since all we have is the authorisation code from
      // the social provider
    }

    // events such as sign out are in the
    // session recipe pre API hook (See the info box below)

    return {
      requestInit,
      url,
    };
  },
});
```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="Mobile" value="mobile">
<DependentContent group="mobile-frameworks" label="Mobile framework">
<ContentOption title="ReactNative" value="reactnative">
```tsx
import SuperTokens from "supertokens-react-native";

SuperTokens.init({
  apiDomain: "...",
  preAPIHook: async (context) => {
    let requestInit = context.requestInit;

    if (context.action === "REFRESH_SESSION") {
      requestInit.headers = {
        ...requestInit.headers,
        customHeader: "custom-header",
      };
    } else if (context.action === "SIGN_OUT") {
      requestInit.headers = {
        ...requestInit.headers,
        customHeader: "custom-header",
      };
    }

    return {
      ...context,
      requestInit,
    };
  },
});
```
</ContentOption>
<ContentOption title="Android" value="android">
```kotlin
import android.app.Application
import com.supertokens.session.CustomHeaderProvider
import com.supertokens.session.SuperTokens

class MainApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        SuperTokens.Builder(applicationContext, "...").customHeaderProvider(object : CustomHeaderProvider {
            override fun getRequestHeaders(requestType: CustomHeaderProvider.RequestType?): MutableMap<String, String> {
                var headers: MutableMap<String, String> = HashMap()

                if (requestType == CustomHeaderProvider.RequestType.REFRESH) {
                    headers["custom-header"] = "custom-value"
                } else if (requestType == CustomHeaderProvider.RequestType.SIGN_OUT) {
                    headers["custom-header"] = "custom-value"
                }

                return headers
            }
        }).build()
    }
}
```
</ContentOption>
<ContentOption title="iOS" value="ios">
```swift
import UIKit
import SuperTokensIOS

fileprivate class MyApplicationDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        do {
            try SuperTokens.initialize(
                apiDomain: "...",
                preAPIHook: {
                  action, request in

                  let mutableRequest = (request as NSURLRequest).mutableCopy() as! NSMutableURLRequest

                  if action == .REFRESH_SESSION {
                    mutableRequest.addValue("custom-value", forHTTPHeaderField: "custom-header")
                  }
                  
                  if action == .SIGN_OUT {
                    mutableRequest.addValue("custom-value", forHTTPHeaderField: "custom-header")
                  }

                  return mutableRequest.copy() as! URLRequest
                }
            )
        } catch SuperTokensError.initError(let message) {
            // TODO: Handle initialization error
        } catch {
            // Some other error
        }

        return true
    }
    
}
```
</ContentOption>
<ContentOption title="Flutter" value="flutter">
```dart
import 'package:supertokens_flutter/supertokens.dart';

void main() {
    SuperTokens.init(
    apiDomain: "...",
    preAPIHook: (action, req) {
      if (action == APIAction.SIGN_OUT) {
        req.headers["custom-header"] = "custom-value";
      } else if (action == APIAction.REFRESH_TOKEN) {
        req.headers["custom-header"] = "custom-value";
      }
      
      return req;
    },
  );
}
```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

<DependentContent passive group="frontend-custom-ui">
<ContentOption title="Web" value="web">
<div>
Alternatively you could also declare the pre-API hook when calling the function:
</div>
</ContentOption>
</DependentContent>

<CodeGroup passive group="frontend-custom-ui">
<Tab title="Web" value="web">
<DependentContent group="install-method" label="Installation method">
<ContentOption title="npm" value="npm">
```tsx
import EmailPassword from "supertokens-web-js/recipe/emailpassword";

EmailPassword.doesEmailExist({
  email: "...",
  options: {
    preAPIHook: async (input) => {
      let url = input.url;
      let requestInit = input.requestInit;

      // TODO: add your code here

      return { url, requestInit };
    },
  },
});
```
</ContentOption>
<ContentOption title="Script tag" value="script-tag">
```tsx check=false reason="script-tag installation provides SuperTokens globals at runtime"
supertokensEmailPassword.doesEmailExist({
  email: "...",
  options: {
    preAPIHook: async (input) => {
      let url = input.url;
      let requestInit = input.requestInit;

      return { url, requestInit };
    },
  },
});
```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>



</VariantContent>

---


## Redirection callback hook

<VariantContent storageKey="ui-type" value="prebuilt">

Use this function to change where the system redirects the user after certain actions.
For example, you can use this to redirect a user to a specific URL post sign in or sign up.
If you're embedding the UI components in a popup and wish to disable redirection entirely, return `null`.

<CodeGroup group="frontend-prebuilt-ui">
<Tab title="Reactjs" value="reactjs">
```tsx
import EmailPassword from "supertokens-auth-react/recipe/emailpassword";
import SuperTokens from "supertokens-auth-react";

SuperTokens.init({
  appInfo: {
    appName: "SuperTokens",
    apiDomain: "http://localhost:3000",
    websiteDomain: "http://localhost:3000",
  },
  getRedirectionURL: async (context) => {
    if (context.action === "SUCCESS" && context.newSessionCreated) {
      // called on a successful sign in / up. Where should the user go next?
      let redirectToPath = context.redirectToPath;
      if (redirectToPath !== undefined) {
        // we are navigating back to where the user was before they authenticated
        return redirectToPath;
      }
      if (context.createdNewUser) {
        // user signed up
        return "/onboarding";
      } else {
        // user signed in
        return "/dashboard";
      }
    } else if (context.action === "TO_AUTH") {
      // called when the user is not authenticated and needs to be redirected to the auth page.
      return "/auth";
    }
    // return undefined to let the default behaviour play out
    return undefined;
  },
  recipeList: [
    EmailPassword.init({
      getRedirectionURL: async (context) => {
        if (context.action === "RESET_PASSWORD") {
          // called when the user clicked on the forgot password button
        }
        // return undefined to let the default behaviour play out
        return undefined;
      },
    }),
  ],
});
```
</Tab>
<Tab title="Angular" value="angular">
```tsx check=false reason="pre-built UI globals are provided by the host framework"
// this goes in the auth route config of your frontend app (once the pre-built UI script has been loaded)

supertokensUIInit({
  appInfo: {
    appName: "SuperTokens",
    apiDomain: "http://localhost:3000",
    websiteDomain: "http://localhost:3000",
  },
  getRedirectionURL: async (context) => {
    if (context.action === "SUCCESS" && context.newSessionCreated) {
      // called on a successful sign in / up. Where should the user go next?
      let redirectToPath = context.redirectToPath;
      if (redirectToPath !== undefined) {
        // we are navigating back to where the user was before they authenticated
        return redirectToPath;
      }
      if (context.createdNewUser) {
        // user signed up
        return "/onboarding";
      } else {
        // user signed in
        return "/dashboard";
      }
    } else if (context.action === "TO_AUTH") {
      // called when the user is not authenticated and needs to be redirected to the auth page.
      return "/auth";
    }
    // return undefined to let the default behaviour play out
    return undefined;
  },
  recipeList: [
    supertokensUIEmailPassword.init({
      getRedirectionURL: async (context) => {
        if (context.action === "RESET_PASSWORD") {
          // called when the user clicked on the forgot password button
        }
        // return undefined to let the default behaviour play out
        return undefined;
      },
    }),
  ],
});
```
</Tab>
</CodeGroup>

</VariantContent>
<VariantContent storageKey="ui-type" value="custom">

:::warning[Not applicable since you need to build custom UI anyway.]
When you call the functions from the SDK, or call the API directly, you can run custom logic in your own code.
:::

</VariantContent>
