# Azure Pipelines > Automate your frequent localization tasks such as uploading source files and downloading translations. URL: https://store.crowdin.com/azure-pipelines Category: Development Type: Guide Author: Andrii Bodnar Use Azure Pipelines with Crowdin CLI to automate your frequent localization tasks such as uploading source files, downloading translations or anything else you can do with Crowdin CLI. Azure Pipelines can be connected with Crowdin through the [Crowdin CLI](https://crowdin.github.io/crowdin-cli/). **Example pipeline configuration:** ```yml trigger: branches: include: - refs/heads/* paths: include: - locales/en/*.json variables: BRANCH_NAME: $[replace(variables['Build.SourceBranch'], 'refs/heads/', '')] jobs: - job: Crowdin pool: vmImage: ubuntu-latest steps: - task: NodeTool@0 displayName: 'Install Node.js' inputs: versionSpec: '22.x' - script: npm install -g @crowdin/cli - script: | crowdin push --no-progress -b $(BRANCH_NAME) \ -T $(CROWDIN_TOKEN) \ -i $(PROJECT_ID) \ -s "locales/en/*json" \ -t "locales/%two_letters_code%/%original_file_name%" \ / ``` In this example, the pipeline will be triggered on branch push filtering by file path. Then you need to set up Node and install Crowdin [CLI NPM package](https://www.npmjs.com/package/@crowdin/cli) globally. After the CLI installation, you can execute any CLI command. Use your Crowdin Project ID, and access token, and specify source and translation files. To securely store your Crowdin Personal Access Token and Project ID, you need to configure it as a [Secret Variables](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch#secret-variables) in your pipeline. More information about [Crowdin CLI commands](https://crowdin.github.io/crowdin-cli/commands/crowdin). **`crowdin.yml` configuration file example:** ```yml "project_id_env": "PROJECT_ID" "api_token_env": "CROWDIN_TOKEN" "base_path": "." "preserve_hierarchy": true "files": [ { "source": "*.md", "translation": "%two_letters_code%.md" } ] ``` See [Configuration File](https://support.crowdin.com/developer/configuration-file/) for more information. ## Automate Azure Pipelines on translation updates Notify your Azure Pipeline when there are new translations and that the build is required. This section describes setting up a Crowdin webhook to trigger the pipeline automatically. To trigger an Azure Pipeline, you need to send a POST request to the Azure DevOps REST API: ```bash curl \ -X POST \ -H "Content-Type: application/json" \ -H "Authorization: Basic BASE64_ENCODED_PAT" \ https://dev.azure.com/{organization}/{project}/_apis/build/builds?api-version=7.1 \ -d '{"definition": {"id": pipelineId}}' ``` Where: - `{organization}` - your Azure DevOps organization name - `{project}` - your project name - `pipelineId` - the ID of your pipeline (you can find it in the URL when viewing your pipeline: `https://dev.azure.com/{organization}/{project}/_build?definitionId={pipelineId}`) - `BASE64_ENCODED_PAT` - Base64-encoded string in format `:YOUR_PERSONAL_ACCESS_TOKEN` To get the Base64-encoded PAT, run: ```bash echo -n ":YOUR_PERSONAL_ACCESS_TOKEN" | base64 ``` :::info Make sure to create a [Personal Access Token (PAT)](https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate) in Azure DevOps with the scope `Build (Read & Execute)` to allow Crowdin to trigger your pipeline. ::: We will configure Crowdin to send this request without any middleware, just by setting up the webhook on a needed event (e.g. File is 100% translated). Depending on a Crowdin Edition you use, please check the documentation on how to create a webhook in [crowdin.com](https://support.crowdin.com/webhooks/) and [Crowdin Enterprise](https://support.crowdin.com/enterprise/webhooks/). **Below is an example of a fully configured Crowdin webhook:** - URL: `https://dev.azure.com/{organization}/{project}/_apis/build/builds?api-version=7.1` - HTTP Method: POST - Content Type: `application/json` - Headers: `Authorization: Basic {BASE64_ENCODED_PAT}` - Payload: ```json { "definition": { "id": pipelineId }, "templateParameters": { "fileName": "{{fileName}}", "language": "{{targetLanguageId}}", "projectId": "{{projectId}}" } } ``` :::info - Replace `pipelineId` with your actual pipeline ID number (e.g., `42`), not as a string. - The `templateParameters` field allows you to pass data from Crowdin's webhook payload to your pipeline. Crowdin will automatically replace the placeholders (e.g., `{{fileName}}`, `{{targetLanguageId}}`) with actual values from the event payload. See the [Webhooks documentation](https://support.crowdin.com/developer/webhooks/) for available payload fields. - You can omit `templateParameters` if you don't need to pass any data to your pipeline. ::: **Pipeline example for webhook-triggered builds:** ```yml trigger: none # Disable automatic triggers parameters: - name: fileName type: string default: '' - name: language type: string default: '' - name: projectId type: number default: 0 jobs: - job: Crowdin pool: vmImage: ubuntu-latest steps: - task: NodeTool@0 displayName: 'Install Node.js' inputs: versionSpec: '22.x' - script: npm install -g @crowdin/cli displayName: 'Install Crowdin CLI' - script: | echo "File translated: ${{ parameters.fileName }}" echo "Language: ${{ parameters.language }}" echo "Project ID: ${{ parameters.projectId }}" displayName: 'Display webhook data' - script: | crowdin download --no-progress \ -T $(CROWDIN_TOKEN) \ -i $(PROJECT_ID) \ -l ${{ parameters.language }} \ displayName: 'Download translations from Crowdin' ```