> For the complete documentation index, see [llms.txt](https://ayakaleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ayakaleaf-pro.ayaka.space/on-premises/configuration/overleaf-toolkit/dropbox-synchronisation.md).

# Dropbox Synchronisation

{% hint style="info" %}
This feature is developed by [ayaka-notes/ayakaleaf-pro](https://github.com/ayaka-notes/ayakaleaf-pro). It is introduced in v6.3.1 as an early preview and will be officially released in v6.4.0, so its configuration and behavior may still change. We need your feedback if you have any problem.
{% endhint %}

Dropbox Synchronisation keeps the projects of a user in sync with their Dropbox, like on Overleaf Cloud: once a user links their Dropbox account, each of their projects appears as a folder in `Apps/<your Dropbox app>/`, changes in Overleaf are sent to Dropbox, and changes made in Dropbox come back to Overleaf.

### Setup Dropbox Synchronisation

{% hint style="warning" %}
You need to enable [git-bridge](/on-premises/configuration/overleaf-toolkit/git-integration.md) first: without it, the account settings hide the project sync section.

{% code title="config/overleaf.rc" %}

```dotenv
GIT_BRIDGE_ENABLED=true
```

{% endcode %}
{% endhint %}

Create an app in the [Dropbox App Console](https://www.dropbox.com/developers/apps), signed in with the Dropbox account that will own the app:

1. Click **Create app**, then fill in the page:
   * **1. Choose an API**: select **Scoped access**.
   * **2. Choose the type of access you need**: select **App folder**, not **Full Dropbox**. Overleaf only syncs inside the folder of the app.
   * **3. Name your app**: enter a name, e.g. `Overleaf`. It must be unique on Dropbox. Each user's projects appear in `Apps/<name of your app>/` in their Dropbox, and this name is `DROPBOX_APP_NAME` below.
   * Click **Create app**. The app opens on its **Settings** tab.
2. On the **Permissions** tab, under **Files and folders**, check `files.metadata.write`, `files.content.write` and `files.content.read`. `account_info.read` and `files.metadata.read` are checked with them and cannot be unchecked. Do not check other permissions.
3. Click **Submit** in the bar at the bottom of the **Permissions** tab. **Without Submit the permissions are not saved**, and Dropbox refuses to sync files for the users who link their account.

<figure><img src="https://2052729351-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyLFrF2L1FakWXkhqpOnS%2Fuploads%2Fgit-blob-f8e7c2c6c4a060b1200b4fa54db109d10494f9ee%2Fdropbox-app-permissions.png?alt=media" alt=""><figcaption><p>Dropbox App Console: the permissions to check, saved with Submit</p></figcaption></figure>

4. On the **Settings** tab, under **OAuth 2**, enter `${OVERLEAF_SITE_URL}/user/dropbox/oauth/callback` in **Redirect URIs**, then **click Add**. Typing the URI is not enough: it is only saved once it shows in the list above the field.

<figure><img src="https://2052729351-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyLFrF2L1FakWXkhqpOnS%2Fuploads%2Fgit-blob-a98bd9343a0f4fe61533e3e7df3aaff73172d69f%2Fdropbox-app-redirect-uri.png?alt=media" alt=""><figcaption><p>Dropbox App Console: enter the redirect URI, then click Add</p></figcaption></figure>

5. On the **Settings** tab, under **Webhooks**, enter `${OVERLEAF_SITE_URL}/dropbox/webhook` in **Webhook URIs**, then **click Add** as well. Dropbox calls it right away to check it, so Overleaf must already be running with the settings below and be reachable from the internet (see [Webhook](#webhook)). Its status shows **Enabled** once the check passes.

Copy the **App key** and the **App secret** (click **Show**) from the **Settings** tab, then add the following settings to your overleaf env var files. You can add the webhook (step 5) after Overleaf runs with them.

{% code title="config/variables.env" overflow="wrap" %}

```dotenv
# used to encrypt the user's Dropbox refresh token.
# How to generate: `openssl rand -hex 32`
DROPBOX_TOKEN_CIPHER_PASSWORD=0123456789ABCDEFG # changed to yours

# Dropbox Sync Settings
DROPBOX_ENABLED=true
DROPBOX_APP_KEY=
DROPBOX_APP_SECRET=
# the name of your Dropbox app (step 1), which is the folder name in Apps/
DROPBOX_APP_NAME=Overleaf

# OAuth callback is: ${OVERLEAF_SITE_URL}/user/dropbox/oauth/callback
# Webhook is: ${OVERLEAF_SITE_URL}/dropbox/webhook
# (Optional) DROPBOX_SYNC_PROXY_URL=http://10.0.0.1:10808
```

{% endcode %}

{% hint style="warning" %}

* Before configuring the redirect URI and the webhook, make sure `OVERLEAF_SITE_URL` is set correctly.
* Dropbox fixes the permissions of a token when the user links their account: submitting permissions does not change existing tokens. Users who linked before the permissions were submitted, or before you changed them, have to unlink and link their Dropbox account again.
* A new app is in **Development** status. If **Development users** on the **Settings** tab shows **Only you**, only your Dropbox account can be linked: click **Enable additional users** to let other users link theirs. It then shows how many users linked, e.g. `1 / 500`: **a Development app takes at most 500 users**. For more users, click **Apply for production**, and Dropbox reviews the app.
  {% endhint %}

If you are in a region with restricted network access, you may need to configure a proxy to access Dropbox. Set the following environment variable: `DROPBOX_SYNC_PROXY_URL=http://10.0.0.1:10808`. It must be a standard HTTP/HTTPS forward proxy, and must not use `127.0.0.1`.

#### Create the database indexes

Run this once, before users link their Dropbox accounts. Server CE and Server Pro do not create the indexes that Dropbox sync uses, so without them every sync lookup scans the collection.

Toolkit users: run `bin/mongo`. Docker Compose users: run `docker compose exec mongo mongosh sharelatex`. Then paste:

```js
db.dropboxEntities.createIndex(
  { 'overleaf.userId': 1, 'dropbox.id': 1 },
  { name: 'overleaf.userId_1_dropbox.id_1', unique: true,
    partialFilterExpression: { 'dropbox.id': { $exists: true } } })
db.dropboxEntities.createIndex(
  { 'overleaf.userId': 1, 'overleaf.id': 1 },
  { name: 'overleaf.userId_1_overleaf.id_1', unique: true,
    partialFilterExpression: { 'overleaf.id': { $exists: true } } })
db.dropboxEntities.createIndex({ 'overleaf.userId': 1, 'dropbox.pathLower': 'hashed' })
db.dropboxProjects.createIndex({ userId: 1, projectId: 1 }, { name: 'projectId_userId_1', unique: true })
db.dropboxProjects.createIndex({ userId: 1, dropboxId: 1 }, { name: 'userId_dropboxId_1', unique: true })
```

Running it again is harmless: MongoDB skips indexes that already exist.

{% hint style="danger" %}
Do not run the `dropboxEntities` migrations of `tools/migrations` instead: `20220825160708_recreate_dropboxEntities` drops the collection, which deletes the sync state of every user.
{% endhint %}

### Webhook

Dropbox tells Overleaf about changes in Dropbox with a webhook, so they show up in Overleaf within seconds. The webhook goes to your site's address, `${OVERLEAF_SITE_URL}/dropbox/webhook`, no extra port is needed, but **Dropbox must be able to reach it from the internet**. When you add it in the App Console, Dropbox checks it right away.

Without a webhook, for example on a server that Dropbox cannot reach, changes in Overleaf are still sent to Dropbox, but changes in Dropbox only come back when a user clicks *sync this project now* in the Dropbox dialog of the editor.

### How syncing works

* **Linking**: when a user links their Dropbox account, the projects they own are sent to Dropbox. Projects shared with them appear in Dropbox with their next change.
* **Overleaf to Dropbox**: new files, renames, moves, deletions and project renames are sent right away. Edits in the editor are sent once Overleaf saves them to its storage, a few minutes after everyone has left the project. To send them earlier, click *sync this project now* in the Dropbox dialog of the editor (once per minute).
* **Dropbox to Overleaf**: new and changed files, new folders and deletions in a project folder are applied to the project. A new folder at the top of the app folder becomes a new project. Deleting a project folder in Dropbox marks the project as deleted in Overleaf.
* **Conflicts**: when a file changes in both places at the same time, the last change wins. Dropbox may keep the other version as a *conflicted copy*.
* **Collaborators**: collaborators who link their Dropbox get the projects shared with them. Read-only viewers and reviewers get the project, but their changes in Dropbox do not sync back to Overleaf.
* **Ignored files**: files Overleaf does not sync, like build output (`.aux`, `.log`, …), `.DS_Store` or Python virtual environments, stay in Dropbox only.

### Q\&A

<details>

<summary>Why can a user not link their Dropbox account?</summary>

**Answer:**

* A Dropbox folder that Overleaf does not know yet is matched to a project by its name, so a user whose projects share a name is asked to rename them first. Names are compared without case, and archived and trashed projects count too.
* A Dropbox account can only be linked to one Overleaf account.

</details>

<details>

<summary>Why was a Dropbox account unlinked?</summary>

**Answer:** Overleaf unlinks a Dropbox account when Dropbox refuses its token (for example after the user removed the app in Dropbox), when the Dropbox is full, or when Dropbox suspended the account. A notification in the project list tells the user which of these happened, until they link the account again. The user can link it again once the problem is solved.

</details>

<details>

<summary>Can I rename a project folder in Dropbox?</summary>

**Answer:** Please rename the project in Overleaf instead: its folder in Dropbox is renamed too. For Overleaf, renaming the folder in Dropbox deletes the project folder and creates a new one, so the old project is marked as deleted and a new project is created from the files.

</details>

<details>

<summary>Why are some project folders numbered, like "Thesis (1)"?</summary>

**Answer:** Every project has a folder of its own, also when two projects have the same name. Dropbox cannot hold two folders with the same name, so it adds a number to the folder made later. The number depends on which names were free in Dropbox at that moment, not on which project is older. Overleaf knows the folder of each project, so changes never go to the folder of another project with the same name.

An uploaded project whose name is already taken is named with a number in Overleaf as well, for example "Thesis (1)".

</details>

<details>

<summary>What happens when I delete a project folder in Dropbox?</summary>

**Answer:**

* If no other project has the name of the folder, the project is marked as deleted in Overleaf. Its files and history are kept.
* If several projects have that name, Overleaf cannot tell which one the folder belonged to. It unlinks the Dropbox account and shows a notification asking to rename the projects. Give projects distinct names before deleting their folders in Dropbox.
* A numbered folder, like "Thesis (1)", matches no project name, so deleting it does not change the project in Overleaf. Click *sync this project now* in the Dropbox dialog of the editor to send the project to Dropbox again.

</details>

<details>

<summary>What happens in Dropbox when I delete a project in Overleaf?</summary>

**Answer:** Nothing, its folder stays in Dropbox. Delete the folder in Dropbox if you no longer need it.

</details>

<details>

<summary>What happens to changes in Dropbox while a project is archived or trashed?</summary>

**Answer:** They are not applied to the project, and restoring the project does not bring them in either. After restoring, Overleaf stops sending its changes of the files that were changed in Dropbox meanwhile, so the two sides differ.

To bring such a file back in sync, save it once more in Dropbox. Overleaf then takes the Dropbox version: changes made to the file in Overleaf since restoring are replaced, and stay in the project history. Restore a project before you change it in Dropbox.

</details>

<details>

<summary>Why does the Dropbox link of the editor open the Dropbox home page?</summary>

**Answer:** The link goes to `Apps/<app folder>/<project>` on dropbox.com, as on Overleaf Cloud. When Dropbox shows its `Apps` folder under a translated name, for example `应用` in Chinese, the link does not find the folder and Dropbox opens its home page instead. Open the project folder from the translated `Apps` folder in Dropbox.

</details>

<details>

<summary>Why are some files of a project missing in Dropbox?</summary>

**Answer:** Changes made while the sync service was not running, for example while it restarted, are not sent to Dropbox later. Click *sync this project now* in the Dropbox dialog of the editor: it sends the whole project again.

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://ayakaleaf-pro.ayaka.space/on-premises/configuration/overleaf-toolkit/dropbox-synchronisation.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
