diff --git a/jobs/tools/jenkins-jobs-builder.yaml b/jobs/tools/jenkins-jobs-builder.yaml
index 24f7666..9b81f19 100644
--- a/jobs/tools/jenkins-jobs-builder.yaml
+++ b/jobs/tools/jenkins-jobs-builder.yaml
@@ -1,36 +1,46 @@
 - job:
     name: jenkins-tools/swh-jenkins-jobs-builder
     project-type: pipeline
     description: Update jenkins jobs
     node: built-in
     auth-token: "ph4br1cat0r"
 
     properties:
       - build-discarder:
           days-to-keep: 7
 
     dsl: |
       pipeline {
         agent any
 
         stages {
 
           stage('Checkout Repository') {
             steps {
               checkout([
                 $class: 'GitSCM',
                 branches: [[name: 'gitlab-integration']],
                 userRemoteConfigs: [[
                   url: "http://forge.softwareheritage.org/source/swh-jenkins-jobs.git",
                 ]],
               ])
             }
           }
 
           stage('Update Jenkins jobs') {
             steps {
               sh('tox -- update --delete-old')
             }
           }
+
+          stage('Setup jenkins integration on gitlab') {
+            steps {
+              script {
+                build(
+                  job: '/jenkins-tools/setup-gitlab-webhooks',
+                )
+              }
+            }
+          }
         }
       }
diff --git a/jobs/tools/setup-gitlab-webhooks.groovy.j2 b/jobs/tools/setup-gitlab-webhooks.groovy.j2
new file mode 100644
index 0000000..8c0c58b
--- /dev/null
+++ b/jobs/tools/setup-gitlab-webhooks.groovy.j2
@@ -0,0 +1,80 @@
+pipeline {
+  agent any
+
+  environment {
+    GITLAB_TOKEN = credentials("jenkins-gitlab-token")
+  }
+
+  stages {
+
+    stage('Checkout Repository') {
+      steps {
+        checkout([
+          $class: 'GitSCM',
+          branches: [[name: 'gitlab-integration']],
+          userRemoteConfigs: [[
+            url: "http://forge.softwareheritage.org/source/swh-jenkins-jobs.git",
+          ]],
+        ])
+      }
+    }
+
+    stage('Setup gitlab integration') {
+      steps {
+        script {
+          projects = readYaml(file: 'jobs/swh-packages.yaml')
+          for (project in projects) {
+            if (project.containsKey("project")) {
+              def jenkinsFolder = project.get('project').get('name')
+              def repoName= project.get('project').get('repo_name')
+              def webhookUrl = "${jenkins_url}/project/${jenkinsFolder}/gitlab-tests"
+              def gitlabProjectName = "swh/devel/${repoName}"
+              setupGitlabWebhook(gitlabProjectName, webhookUrl)
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+void setupGitlabWebhook(gitlabProjectName, webhookUrl, pushEvents = true,
+                        mergeRequestEvents = true, tagPushEvents = false) {
+
+  def gitlabProjectEncoded = java.net.URLEncoder.encode(gitlabProjectName, "UTF-8")
+  def payload = """
+    {
+      "id": "${gitlabProjectEncoded}",
+      "url": "${webhookUrl}",
+      "push_events": "${pushEvents}",
+      "merge_requests_events": "${mergeRequestEvents}",
+      "tag_push_events": "${tagPushEvents}",
+      "token": "{{jenkins_token}}"
+    }
+    """
+
+    def url = "${gitlab_url}/api/v4/projects/${gitlabProjectEncoded}/hooks"
+
+    // get current webhooks of the gitlab project
+    def response = httpRequest httpMode: 'GET', url: url,
+          contentType: 'APPLICATION_JSON',
+          customHeaders: [[name: 'Authorization', value: "Bearer $GITLAB_TOKEN"]]
+
+    def hooks = readJSON text: response.content
+    for (hook in hooks) {
+      if (hook.url == webhookUrl) {
+        // update previously set webhook for jenkins job
+        httpRequest httpMode: 'PUT', url: "${url}/${hook.id}",
+          contentType: 'APPLICATION_JSON', requestBody: payload,
+          customHeaders: [[name: 'Authorization', value: "Bearer $GITLAB_TOKEN"]]
+        return
+      }
+    }
+
+    // add webhook for jenkins job
+    httpRequest httpMode: 'POST', url: url,
+      contentType: 'APPLICATION_JSON', requestBody: payload,
+      customHeaders: [[name: 'Authorization', value: "Bearer $GITLAB_TOKEN"]]
+
+}
+
diff --git a/jobs/tools/setup-gitlab-webhooks.yaml b/jobs/tools/setup-gitlab-webhooks.yaml
new file mode 100644
index 0000000..1dc7f6b
--- /dev/null
+++ b/jobs/tools/setup-gitlab-webhooks.yaml
@@ -0,0 +1,30 @@
+- job-template:
+    name: jenkins-tools/{name}
+    project-type: pipeline
+    description: Setup Jenkins integration for a GitLab repository
+    node: built-in
+    # secret jenkins token is generated when executing tox
+    jenkins_token: !include-raw: jobs/templates/jenkins-token
+    parameters:
+      - credentials:
+          name: gitlab_token
+          type: secrettext
+          default: jenkins-gitlab-token
+          description: GitLab token used by Jenkins to query GitLab API
+      - string:
+          name: gitlab_url
+          description: URL of GitLab instance
+          default: https://gitlab-staging.swh.network
+      - string:
+          name: jenkins_url
+          description: URL of Jenkins instance
+          default: https://jenkins.softwareheritage.org
+
+    dsl: !include-jinja2: setup-gitlab-webhooks.groovy.j2
+
+# we use a project and a job template here as we need jinja2 processing
+# to inline the generated jenkins token into the pipeline groovy script
+- project:
+    name: setup-gitlab-webhooks
+    jobs:
+      - "jenkins-tools/{name}"