đ Executive Summary
TL;DR: This article provides a step-by-step guide to automate syncing Figma comments directly into a dedicated Slack channel using a Python script. This solution eliminates manual polling and context-switching, significantly improving design operations velocity and fostering near real-time feedback loops.
đŻ Key Takeaways
- Figma API access requires a Personal Access Token from account settings and the specific File Key extracted from the design fileâs URL.
- A Slack App must be created with the
chat:writebot token scope and installed to the workspace to enable the bot to post messages. - Environment variables, managed via
python-dotenvand aconfig.envfile, are crucial for securely storing sensitive API tokens and IDs. - A state file (
last\_checked\_timestamp.txt) is implemented to track the last successful check time, preventing duplicate comment notifications on subsequent script runs. - Handling Figma API timestamps involves converting them to timezone-aware datetime objects (UTC) to ensure accurate comparison and filtering of new comments.
- The Python script can be scheduled for periodic execution using traditional cron jobs or deployed as a serverless function (e.g., AWS Lambda) for robust automation.
Syncing Figma Comments to Slack for Better Design Ops
Hey team, Darian here. I want to talk about a small but mighty automation I set up thatâs saved meâand our design teamâa ton of context-switching. I used to manually poll our main Figma file for new feedback before every stand-up. It felt like I was wasting at least an hour or two a week just refreshing a browser tab. No more. By piping Figma comments directly into a dedicated Slack channel, weâve closed the feedback loop and can spot critical design issues in near real-time. Itâs a classic Design Ops win, and I want to show you how to build it.
This isnât just about convenience; itâs about velocity. Faster feedback means faster iterations and a better product. Letâs get this done.
Prerequisites
- Figma Account: Youâll need a Figma account with access to the file you want to monitor.
- Slack Workspace: You need permissions to create a new Slack App or have an admin do it for you.
- Python 3 Environment: A place to run our script. I trust you know how to set this up.
- Scheduling Mechanism: A way to run the script periodically. Weâll discuss using cron, but this could easily be a serverless function (AWS Lambda, Google Cloud Functions, etc.).
The Guide: Step-by-Step
Step 1: Get Your Figma Credentials
First, we need to tell our script how to access Figma. We need two things: a Personal Access Token and a File Key.
- Personal Access Token: In Figma, go to your main menu > Help and account > Account settings. Scroll down to the âPersonal access tokensâ section. Create a new token, give it a descriptive name like âSlackCommentSync,â and copy it somewhere safe. This is your password to the API.
-
File Key: Open the Figma file you want to monitor. Look at the URL in your browser. It will look something like
figma.com/file/{file_key}/Your-Project-Name. That long alphanumeric string in the middle is your File Key. Grab that.
Step 2: Create a Slack App
Next, we need a bot to post messages in Slack for us.
- Navigate to api.slack.com/apps and click âCreate New App.â Choose âFrom scratch.â
- Give your app a name (e.g., âFigma Comment Botâ) and select your workspace.
- In the sidebar, go to âOAuth & Permissions.â Scroll down to âScopesâ and under âBot Token Scopes,â click âAdd an OAuth Scope.â Add the
chat:writepermission. This allows your bot to post messages. - Scroll back up and click âInstall to Workspace.â Authorize it.
- After authorizing, youâll see a âBot User OAuth Tokenâ that starts with
xoxb-. Copy this. This is your botâs password. - Finally, create a new Slack channel (e.g.,
#figma-feedback) and invite your newly created bot to it. You can find the bot by its app name.
Step 3: The Python Script
Alright, letâs get to the code. Iâll skip the standard virtualenv setup since you likely have your own workflow for that. Just make sure youâre in an isolated environment. Youâll need to install a couple of libraries; you can do this with pip for requests to handle our API calls and python-dotenv to manage our secrets securely.
Create a file named config.env in your project directory. This is where weâll store our secrets so they arenât hardcoded in the script. Itâs much safer.
FIGMA_TOKEN="your_figma_personal_access_token_here"
SLACK_TOKEN="your_slack_bot_token_starting_with_xoxb"
FIGMA_FILE_KEY="your_figma_file_key_from_url"
SLACK_CHANNEL_ID="YOUR_SLACK_CHANNEL_ID"
To get the SLACK_CHANNEL_ID, right-click the channel name in Slack and select âCopy link.â The last part of the URL, starting with a âCâ, is the ID.
Now, hereâs the main script, letâs call it sync_comments.py. Iâve added comments to explain the logic as we go.
import os
import requests
from datetime import datetime, timezone, timedelta
from dotenv import load_dotenv
# --- Configuration & Setup ---
# Load environment variables from config.env file
load_dotenv('config.env')
FIGMA_TOKEN = os.getenv('FIGMA_TOKEN')
SLACK_TOKEN = os.getenv('SLACK_TOKEN')
FIGMA_FILE_KEY = os.getenv('FIGMA_FILE_KEY')
SLACK_CHANNEL = os.getenv('SLACK_CHANNEL_ID')
# State file to remember the last time we checked for comments
STATE_FILE = 'last_checked_timestamp.txt'
# --- Helper Functions ---
def get_last_check_time():
"""Reads the last successful check time from the state file."""
try:
with open(STATE_FILE, 'r') as f:
return f.read().strip()
except FileNotFoundError:
# If the file doesn't exist, check comments from the last hour on first run.
# This prevents spamming the channel with all historical comments.
return (datetime.now(timezone.utc) - timedelta(hours=1)).isoformat()
def update_last_check_time(timestamp_str):
"""Writes the current check time to the state file."""
with open(STATE_FILE, 'w') as f:
f.write(timestamp_str)
# --- Core Logic ---
def fetch_figma_comments():
"""Fetches all comments from the specified Figma file."""
url = f"https://api.figma.com/v1/files/{FIGMA_FILE_KEY}/comments"
headers = {'X-FIGMA-TOKEN': FIGMA_TOKEN}
try:
response = requests.get(url, headers=headers)
response.raise_for_status() # Raises an exception for bad status codes (4xx or 5xx)
return response.json().get('comments', [])
except requests.exceptions.RequestException as e:
print(f"Error fetching Figma comments: {e}")
return []
def post_to_slack(message):
"""Posts a formatted message to the configured Slack channel."""
url = "https://slack.com/api/chat.postMessage"
headers = {'Authorization': f"Bearer {SLACK_TOKEN}"}
payload = {
'channel': SLACK_CHANNEL,
'text': message, # Fallback text for notifications
'blocks': [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": message
}
}
]
}
try:
response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
except requests.exceptions.RequestException as e:
print(f"Error posting to Slack: {e}")
def main():
"""Main execution function."""
print("Starting Figma comment sync...")
last_check_iso = get_last_check_time()
last_check_dt = datetime.fromisoformat(last_check_iso.replace('Z', '+00:00'))
current_check_time = datetime.now(timezone.utc)
all_comments = fetch_figma_comments()
if not all_comments:
print("No comments found or API error.")
return
new_comments_found = False
for comment in sorted(all_comments, key=lambda c: c['created_at']):
comment_dt = datetime.fromisoformat(comment['created_at'].replace('Z', '+00:00'))
# We only care about comments created after our last check
if comment_dt > last_check_dt:
new_comments_found = True
user_name = comment['user']['handle']
comment_text = comment['message']
# Figma's API doesn't give a direct link, but we can construct one
node_id = comment.get('client_meta', {}).get('node_id')
link = f"https://www.figma.com/file/{FIGMA_FILE_KEY}?node-id={node_id}" if node_id else "Link not available"
message = (
f":figma: *New Figma Comment from {user_name}*\n"
f"> {comment_text}\n"
f"<{link}|View in Figma>"
)
print(f"Found new comment from {user_name}. Posting to Slack.")
post_to_slack(message)
if not new_comments_found:
print("No new comments since last check.")
# Update the state file with the time this script started running
update_last_check_time(current_check_time.isoformat())
print("Sync complete.")
if __name__ == "__main__":
main()
Pro Tip: In my production setups, I replace the simple text file for state management with something more robust, like a Redis key or a small database entry. This avoids file permission issues and race conditions if the script ever runs in parallel, especially in a serverless environment. But for getting started, a text file is perfectly fine.
Step 4: Schedule the Script
You donât want to run this manually. The goal is automation. The classic way is using cron on a server.
You can set up a cron job to run this script, say, every 15 minutes. The command would look something like this, assuming your script is in your userâs project folder.
*/15 * * * * python3 /path/to/your/project/sync_comments.py
Alternatively, a more modern approach is to deploy this as a serverless function (like AWS Lambda) and trigger it on a schedule. This is often more reliable and cost-effective than managing a dedicated server for a small script.
Common Pitfalls
Hereâs where Iâve stumbled in the past, so you donât have to:
-
Slack Scopes are Wrong: The most common mistake is forgetting the OAuth scopes. Youâll create the bot, get the token, run the script, and⌠nothing. Itâs almost always because you forgot to give your bot the
chat:writepermission in the Slack app settings and then reinstalling the app to your workspace. - Timezone Hell: Figmaâs API returns timestamps in UTC (ISO 8601 format). My script handles this using Pythonâs timezone-aware datetime objects, but itâs a critical detail. If you modify the script, make sure all your time comparisons are timezone-aware to avoid missing comments or sending duplicates.
- Initial Run Spam: The first time you run the script, the state file wonât exist. If you donât handle this case, you could end up posting every single comment ever made on the file. My script defaults to only grabbing comments from the last hour on its first run to prevent this.
- Rate Limiting: Both Figma and Slack have API rate limits. For a simple check every 5-15 minutes, youâll be fine. But if you try to run it every second or monitor dozens of files with one token, you might get temporarily blocked. Keep the schedule reasonable.
Conclusion
And thatâs it. A simple Python script that bridges a critical gap between design and development. This isnât just about notifications; itâs about creating a culture of responsive feedback and reducing the friction of communication. Youâve now got a solid foundation you can build onâmaybe add filtering for comments that @-mention a specific team, or route feedback to different channels based on the page name in Figma. Go make your designers happy.
Cheers,
Darian Vance
đ Read the original article on TechResolve.blog
â Support my work
If this article helped you, you can buy me a coffee:

Top comments (0)