info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
description: "GitLab's development guidelines for Integrations"
---
# Integrations development guide **(FREE)**
This page provides development guidelines for implementing [GitLab integrations](../../user/project/integrations/index.md),
which are part of our [main Rails project](https://gitlab.com/gitlab-org/gitlab).
Also see our [direction page](https://about.gitlab.com/direction/ecosystem/integrations/) for an overview of our strategy around integrations.
This guide is a work in progress. You're welcome to ping `@gitlab-org/ecosystem-stage/integrations`
if you need clarification or spot any outdated information.
## Add a new integration
### Define the integration
1. Add a new model in `app/models/integrations` extending from `Integration`.
- For example, `Integrations::FooBar` in `app/models/integrations/foo_bar.rb`.
- For certain types of integrations, you can also build on these base classes:
-`Integrations::BaseChatNotification`
-`Integrations::BaseIssueTracker`
-`Integrations::BaseMonitoring`
-`Integrations::BaseSlashCommands`
- For integrations that primarily trigger HTTP calls to external services, you can
also use the `Integrations::HasWebHook` concern. This reuses the [webhook functionality](../../user/project/integrations/webhooks.md)
in GitLab through an associated `ServiceHook` model, and automatically records request logs
which can be viewed in the integration settings.
1. Add the integration's underscored name (`'foo_bar'`) to `Integration::INTEGRATION_NAMES`.
1. Add the integration as an association on `Project`:
1. TEMPORARY: Accommodate the current migration to [rename "services" to "integrations"](#rename-services-to-integrations):
- Add the integration's camel-cased name (`'FooBar'`) to `Gitlab::Integrations::StiType::NAMESPACED_INTEGRATIONS`.
### Define properties
Integrations can define arbitrary properties to store their configuration with the class method `Integration.prop_accessor`.
The values are stored as a serialized JSON hash in the `integrations.properties` column.
For example:
```ruby
module Integrations
class FooBar <Integration
prop_accessor :url
prop_accessor :tags
end
end
```
`Integration.prop_accessor` installs accessor methods on the class. Here we would have `#url`, `#url=` and `#url_changed?`, to manage the `url` field. Fields stored in `Integration#properties` should be accessed by these accessors directly on the model, just like other ActiveRecord attributes.
You should always access the properties through their getters, and not interact with the `properties` hash directly.
You **must not** write to the `properties` hash, you **must** use the generated setter method instead. Direct writes to this
hash are not persisted.
You should also define validations for all your properties.
Also refer to the section [Customize the frontend form](#customize-the-frontend-form) below to see how these properties
are exposed in the frontend form for the integration.
There is an alternative approach using `Integration.data_field`, which you may see in other integrations.
With data fields the values are stored in a separate table per integration. At the moment we don't recommend using this for new integrations.
### Define trigger events
Integrations are triggered by calling their `#execute` method in response to events in GitLab,
which gets passed a payload hash with details about the event.
The supported events have some overlap with [webhook events](../../user/project/integrations/webhook_events.md),
and receive the same payload. You can specify the events you're interested in by overriding
the class method `Integration.supported_events` in your model.
The following events are supported for integrations:
| [Merge request event](../../user/project/integrations/webhook_events.md#merge-request-events) | ✓ | `merge_request` | A merge request is created, updated, or merged.
| [Comment event](../../user/project/integrations/webhook_events.md#comment-events) | | `comment` | A new comment is added.
| [Confidential comment event](../../user/project/integrations/webhook_events.md#comment-events) | | `confidential_note` | A new comment on a confidential issue is added.
| [Pipeline event](../../user/project/integrations/webhook_events.md#pipeline-events) | | `pipeline` | A pipeline status changes.
| [Push event](../../user/project/integrations/webhook_events.md#push-events) | ✓ | `push` | A push is made to the repository.
| [Tag push event](../../user/project/integrations/webhook_events.md#tag-events) | ✓ | `tag_push` | New tags are pushed to the repository.
| Vulnerability event **(ULTIMATE)** | | `vulnerability` | A new, unique vulnerability is recorded.
| [Wiki page event](../../user/project/integrations/webhook_events.md#wiki-page-events) | ✓ | `wiki_page` | A wiki page is created or updated.
#### Event examples
This example defines an integration that responds to `commit` and `merge_request` events:
```ruby
module Integrations
class FooBar <Integration
def self.supported_events
%w[commit merge_request]
end
end
end
```
An integration can also not respond to events, and implement custom functionality some other way:
```ruby
module Integrations
class FooBar <Integration
def self.supported_events
[]
end
end
end
```
### Customize the frontend form
The frontend form is generated dynamically based on metadata defined in the model.
By default, the integration form provides:
- A checkbox to enable or disable the integration.
- Checkboxes for each of the trigger events returned from `Integration#configurable_events`.
You can also add help text at the top of the form by either overriding `Integration#help`,