Skip to main content
For an overview of how CodeRabbit integrates with Git platforms, see Add CodeRabbit to your repository.
Version RequirementsCodeRabbit supports GitLab 16.x and above. Version 15.x may experience unexpected issues such as review comments not being posted or the sign-up process not working at all. We recommend upgrading your GitLab instance to obtain the intended experience.

Getting Started

To integrate your self-managed GitLab with CodeRabbit, we require specific information for the initial setup within your domain. Once this setup is complete, you can log in directly using the OAuth2 flow.
1

Visit CodeRabbit login page

Navigate to the CodeRabbit login page and select Self-Hosted GitLab.CodeRabbit login
2

Enter your GitLab instance URL

Enter the URL of your self-managed GitLab instance and click Submit. We’ll check our database for an existing record of your organization and start the login process if found.Self-hosted Gitlab enterprise connection pageIf your self-managed GitLab instance is not found, we’ll initiate the onboarding process.
3

Choose onboarding method

You can choose between automated or manual onboarding based on your security preferences and administrative access.

Onboarding Options

Self-managed GitLab connection page
Why do we need the Admin Access Token?The admin access token is required to set up a new CodeRabbit bot user within your self-managed instance. The token is needed only once during the initial setup process. Once generated, you can set its minimum expiration period. This is the standard approach used by other products in this category.Note: This does not automatically install the CodeRabbit app across all projects. You will add CodeRabbit manually to the projects you wish to integrate.

Manual Onboarding

For the manual onboarding process, you need to create the CodeRabbit user and the OAuth2 GitLab application. Self-managed GitLab connection page

Creating CodeRabbit User

This feature will work with any user from your organization, but we strongly recommend creating a dedicated user called CodeRabbitAI. This ensures clarity about which user is used for our application and allows for better fine-grained access control.
1

Create the user

Log in with an instance admin account and follow the steps provided in the GitLab documentation to create a new user.
2

Retrieve user information

After the user is created, retrieve the User ID from that user’s profile.
3

Generate access token

Generate an access token for this user. The access token is used to post reviews on merge requests.
Recommendations for the CodeRabbit user: - Use “CodeRabbitAI” as the username for easy identification - Use the CodeRabbit logo as the profile picture for easy recognition - Ensure the user has appropriate permissions for the repositories you want to integrate
If you prefer, you can create a Group Access Token which will create a dedicated user on your behalf. For more information, see Group Access Token.

Creating OAuth2 Application

For self-managed GitLab, we recommend creating an instance-wide application unless you want the reviews to be limited to a single group or user. Follow the steps outlined in the GitLab documentation for creating the application.
OAuth2 Application Requirements:
  • Scopes: api read_user email openid
  • Callback URL: https://app.coderabbit.ai/login

Generating Personal Access Token

GitLab offers an option to generate a personal access token for adding a new user and setting up the application in the self-managed instance.
1

Login to your instance

Login to your self-hosted instance. For automated onboarding, ensure you have admin rights.
2

Access user settings

On the left sidebar, select your avatar, then select Edit profile.
3

Navigate to Access Tokens

On the left sidebar, select Access Tokens.
4

Create new token

Select Add new token.
5

Configure token settings

  • Enter a name and expiry date for the token
  • We need this for the initial setup, so the minimum expiry time is sufficient
  • If you do not enter an expiry date, it defaults to 365 days from the current date
  • Select the required scopes: api, read_api, read_user
6

Generate and save token

Select Create personal access token and note down the token as it will only be displayed once.
GitLab personal access token configuration page

Paste the details and click submit

  • Submit the form.
  • We will handle the setup process for you.
  • On subsequent visits, your setup will be automatically detected, allowing for direct login. CodeRabbit authentication options page

Allow list CodeRabbit IP address

Use this CodeRabbit IP if your instance requires IP allow listing.
Copy
35.222.179.152/32, 34.170.211.100/32

Manual Webhook Installation

For administrators managing many GitLab projects, you can use a script to bulk-install webhooks across all projects.
1

Login to CodeRabbit UI

Login to CodeRabbit UI through your GitLab self-managed instance.
2

Access account settings

On the bottom left sidebar, select Account.
3

Navigate to Webhook Secret

On the left sidebar, select Webhook Secret.
4

Set webhook secret in CodeRabbit UI

Input a webhook secret. This secret will be used by CodeRabbit to verify incoming webhook events from your GitLab instance.Webhook Secret Settings
5

Run script to install webhooks

Use a script to install webhooks across your GitLab projects or groups. Below is a sample script that requires:
  • Your GitLab host URL
  • The CodeRabbit webhook URL: https://coderabbit.ai/gitlabHandler
  • The webhook secret you created in Step 1
  • A GitLab access token with API permissions

gitlab-webhook.sh

Copy
#!/usr/bin/env bash

## gitlab-webhook.sh

# Add a webhook to one project, or every project in a subgroup tree

set -euo pipefail

usage() {
  cat <<EOF
Usage:
  $0 -h <gitlab-host> -u <webhook-url> -s <webhook-secret> \\
     [-t <access-token>] [-A <auth-header>] [-p <project> | -g <group>] [-v]

Required:
  -h  GitLab host (e.g. gitlab.example.com)
  -u  Webhook endpoint URL to receive POSTs
  -s  Webhook secret token (used for signature verification)

Authentication (one of):
  -t  Access token (PAT, project, group or OAuth). If omitted, \$GITLAB_TOKEN is used
  -A  Auth header to use. Default detects:
        PAT → "PRIVATE-TOKEN"
        anything else → "Authorization: Bearer"

Scope (choose one):
  -p  Project ID or full path (e.g. 42 or group/app)
  -g  Group ID or full path, recurse through all subgroups & projects

Options:
  -v  Verbose output (show individual project IDs in final summary)
EOF
  exit 1
}

HOST="" HOOK_URL="" HOOK_SECRET=""
TOKEN="${GITLAB_TOKEN:-}" AUTH_HEADER=""
PROJECT="" GROUP="" VERBOSE=false

while getopts "h:u:s:t:A:p:g:v" opt; do
  case "$opt" in
    h) HOST=$OPTARG ;;
    u) HOOK_URL=$OPTARG ;;
    s) HOOK_SECRET=$OPTARG ;;
    t) TOKEN=$OPTARG ;;
    A) AUTH_HEADER=$OPTARG ;;
    p) PROJECT=$OPTARG ;;
    g) GROUP=$OPTARG ;;
    v) VERBOSE=true ;;
    *) usage ;;
  esac
done

# Mandatory checks

[[ -z $HOST || -z $HOOK_URL || -z $HOOK_SECRET ]] && usage
[[ -n $PROJECT && -n $GROUP ]] && usage
[[ -z $PROJECT && -z $GROUP ]] && usage

# Token handling

if [[ -z $TOKEN ]]; then
  echo "[ERROR] No access token provided. Use -t or set \$GITLAB_TOKEN" >&2
  exit 1
fi

# Choose header if not forced

if [[ -z $AUTH_HEADER ]]; then
  if [[ $TOKEN == glpat-* || $TOKEN == "PAT-"* ]]; then
    AUTH_HEADER="PRIVATE-TOKEN"
  else
    AUTH_HEADER="Authorization: Bearer"
  fi
fi

API="https://${HOST}/api/v4"
CURL_BASE=(curl -sSf --header "${AUTH_HEADER}: ${TOKEN}")

# Track processed projects to avoid duplicates

declare -A PROCESSED_PROJECTS
WEBHOOK_PROJECTS=()
EXISTING_WEBHOOK_PROJECTS=()
TOTAL_PROJECTS_FOUND=0
PROJECTS_PROCESSED=0

url_encode() {
  local string="$1"
  printf '%s' "$string" | sed 's/\//%2F/g; s/ /%20/g; s/@/%40/g; s/:/%3A/g; s/#/%23/g; s/?/%3F/g; s/&/%26/g; s/=/%3D/g; s/+/%2B/g'
}

fetch_paginated() {
  local url=$1
  local page=1
  local per_page=100

  while true; do
    local paginated_url
    if [[ "$url" == *"?"* ]]; then
      paginated_url="${url}&per_page=${per_page}&page=${page}"
    else
      paginated_url="${url}?per_page=${per_page}&page=${page}"
    fi

    local response
    response=$("${CURL_BASE[@]}" "$paginated_url" 2>/dev/null) || {
      echo "[ERROR] Failed to fetch page $page from $url" >&2
      return 1
    }

    if [[ "$response" == "[]" || "$response" == "null" ]]; then
      break
    fi

    local page_results
    page_results=$(echo "$response" | jq -r '.[].id' 2>/dev/null) || {
      echo "[ERROR] Failed to parse JSON response from page $page" >&2
      return 1
    }

    if [[ -z "$page_results" ]]; then
      break
    fi

    local page_count
    page_count=$(echo "$page_results" | wc -l)
    TOTAL_PROJECTS_FOUND=$((TOTAL_PROJECTS_FOUND + page_count))
    echo "[PROGRESS] Found $page_count projects on page $page (total: $TOTAL_PROJECTS_FOUND)" >&2

    echo "$page_results"

    local item_count
    item_count=$(echo "$response" | jq '. | length' 2>/dev/null) || 0
    if [[ "$item_count" -lt "$per_page" ]]; then
      break
    fi

    ((page++))
  done
}

create_hook() {
  local pid=$1

  if [[ -n "${PROCESSED_PROJECTS[$pid]:-}" ]]; then
    return 0
  fi

  PROCESSED_PROJECTS[$pid]=1
  PROJECTS_PROCESSED=$((PROJECTS_PROCESSED + 1))

  local encoded_pid
  if [[ $pid =~ ^[0-9]+$ ]]; then
    encoded_pid=$pid
  else
    encoded_pid=$(url_encode "$pid")
  fi

  local existing_webhooks
  existing_webhooks=$("${CURL_BASE[@]}" "${API}/projects/${encoded_pid}/hooks" 2>/dev/null) || {
    echo "[ERROR] Failed to fetch existing webhooks for project $pid" >&2
    return 1
  }

  if echo "$existing_webhooks" | jq -e --arg url "$HOOK_URL" '.[] | select(.url == $url)' >/dev/null 2>&1; then
    [[ "$VERBOSE" == "true" ]] && echo "[INFO] Webhook already exists for project: $pid" >&2
    EXISTING_WEBHOOK_PROJECTS+=("$pid")
    return 0
  fi

  [[ "$VERBOSE" == "true" ]] && echo "[INFO] Adding webhook to project: $pid" >&2

  "${CURL_BASE[@]}" --request POST \
    --data-urlencode "url=${HOOK_URL}" \
    --data "token=${HOOK_SECRET}" \
    --data "push_events=true" \
    --data "note_events=true" \
    --data "issues_events=true" \
    --data "merge_requests_events=true" \
    --data "enable_ssl_verification=true" \
    "${API}/projects/${encoded_pid}/hooks" \
    > /dev/null

  WEBHOOK_PROJECTS+=("$pid")
}

traverse_group() {
  local gid=$1
  local encoded_gid
  if [[ $gid =~ ^[0-9]+$ ]]; then
    encoded_gid=$gid
  else
    encoded_gid=$(url_encode "$gid")
  fi

  while IFS= read -r pid; do
    [[ -n "$pid" ]] && create_hook "$pid"
  done < <(
    fetch_paginated "${API}/groups/${encoded_gid}/projects?include_subgroups=true"
  )

  while IFS= read -r sg; do
    [[ -n "$sg" ]] && traverse_group "$sg"
  done < <(
    fetch_paginated "${API}/groups/${encoded_gid}/subgroups"
  )
}

echo "[INFO] Starting webhook processing..." >&2

if [[ -n $PROJECT ]]; then
  echo "[INFO] Processing single project: $PROJECT" >&2
  create_hook "$PROJECT"
else
  echo "[INFO] Processing group and subgroups: $GROUP" >&2
  traverse_group "$GROUP"
fi

echo "[INFO] Finished processing all projects" >&2

total_projects=$((${#WEBHOOK_PROJECTS[@]} + ${#EXISTING_WEBHOOK_PROJECTS[@]}))

if [[ $total_projects -eq 0 ]]; then
  echo "[INFO] No projects were processed"
else
  if [[ ${#WEBHOOK_PROJECTS[@]} -gt 0 ]]; then
    if [[ "$VERBOSE" == "true" ]]; then
      echo "[INFO] Webhooks installed successfully on ${#WEBHOOK_PROJECTS[@]} project(s):"
      for pid in "${WEBHOOK_PROJECTS[@]}"; do
        echo "  - Project ID: $pid"
      done
    else
      echo "[INFO] Webhooks installed successfully on ${#WEBHOOK_PROJECTS[@]} project(s)"
    fi
  fi

  if [[ ${#EXISTING_WEBHOOK_PROJECTS[@]} -gt 0 ]]; then
    if [[ "$VERBOSE" == "true" ]]; then
      echo "[INFO] Webhooks already existed on ${#EXISTING_WEBHOOK_PROJECTS[@]} project(s):"
      for pid in "${EXISTING_WEBHOOK_PROJECTS[@]}"; do
        echo "  - Project ID: $pid"
      done
    else
      echo "[INFO] Webhooks already existed on ${#EXISTING_WEBHOOK_PROJECTS[@]} project(s)"
    fi
  fi

  echo "[INFO] Total projects processed: $total_projects"
fi
Copy
# Make sure the script is executable:
chmod +x gitlab-webhook.sh
Example: Install webhook on a single project
Copy
export GITLAB_TOKEN="glpat-xxxxx"
./gitlab-webhook.sh \
  -h "gitlab.example.com" \
  -u "https://coderabbit.ai/gitlabHandler" \
  -s "your-webhook-secret" \
  -p 42
Example: Install webhooks on all projects in a group (including subgroups)
Copy
export GITLAB_TOKEN="glpat-xxxxx"
./gitlab-webhook.sh \
  -h "gitlab.example.com" \
  -u "https://coderabbit.ai/gitlabHandler" \
  -s "your-webhook-secret" \
  -g "mygroup/mysubgroup"
Morty Proxy This is a proxified and sanitized view of the page, visit original site.