# How to Integrate Lovable with Trello

- Tool: Lovable
- Difficulty: Intermediate
- Time required: 35 minutes
- Last updated: March 2026

## TL;DR

Integrating Trello with Lovable requires Edge Functions to proxy the Trello REST API. Store your Trello API key and token in Cloud Secrets, create an Edge Function that reads boards, lists, and cards, and build custom kanban views in Lovable's React frontend. Trello uses a simple board → list → card hierarchy with a clean REST API that makes it one of the more straightforward integrations — ideal for building custom kanban dashboards, card-tracking tools, or team workflow portals.

## Why integrate Trello with Lovable?

Trello's board-list-card model has become the lingua franca of visual project management — it's simple enough for any team to adopt immediately, yet flexible enough through labels, custom fields (Power-Up), due dates, attachments, and checklists to support surprisingly complex workflows. Over 50 million people have used Trello, and many teams use it as their default task tracker precisely because of its low friction and visual clarity.

Building a custom Lovable app around Trello data opens up scenarios where Trello's own interface isn't quite right: client-facing project views that show only specific lists from a board without giving clients full board access, internal operations tools that automate card creation when specific events happen (a new sale, a support ticket escalation, an employee onboarding), custom reporting dashboards that aggregate card counts and ages across multiple boards, and workflow automation triggers that move cards between lists based on data from other systems.

Trello's REST API v1 is one of the simplest project management APIs to work with. Authentication uses API key and token as query parameters rather than headers, board IDs and card IDs are in URLs, and the data model maps directly to the visual interface — boards contain lists, lists contain cards, cards have labels, members, due dates, and checklists. This tutorial builds a full-featured integration covering read operations, card CRUD, and webhook-based real-time updates.

## Before you start

- A Lovable project with Cloud enabled
- A Trello account with at least one board
- A Trello API key — generate at trello.com/power-ups/admin → New → select your workspace → get Key
- A Trello user token — generate by visiting https://trello.com/1/authorize?key=YOUR_API_KEY&name=Lovable+Integration&expiration=never&response_type=token with your actual API key
- Board IDs for the boards you want to integrate — found in the board URL (trello.com/b/BOARD_ID/board-name) or via the API

## Step-by-step guide

### 1. Generate Trello API credentials and store them in Cloud Secrets

Trello uses a two-part authentication system: an API key that identifies your application, and a user token that authorizes access to a specific Trello account's data. The API key is a fixed application credential, while the token is generated per-user and grants the level of access (read-only or read-write) that you specify during the token generation flow.

To get your API key, go to trello.com/power-ups/admin in your browser. Click 'New' to create a developer app, give it a name like 'Lovable Integration', select your workspace, and submit. Your API key appears on the app detail page — copy it. To generate the user token, construct a URL in this format: https://trello.com/1/authorize?key=YOUR_API_KEY&name=Lovable+Integration&expiration=never&response_type=token&scope=read,write — replace YOUR_API_KEY with your actual key, then open that URL in your browser. Trello will ask you to authorize the app and then display a 64-character token — copy it immediately.

In your Lovable project, open the Cloud tab and navigate to Secrets. Add TRELLO_API_KEY with your API key value and TRELLO_TOKEN with your user token. Both are needed for every API request — Trello appends them as query parameters (key=...&token=...) to all request URLs rather than using Authorization headers.

**Expected result:** TRELLO_API_KEY and TRELLO_TOKEN are stored in Cloud Secrets. Both appear in the Secrets list with masked values.

### 2. Create the Trello proxy Edge Function

The Trello API v1 appends authentication as query parameters rather than headers, which means every URL your Edge Function constructs must include key and token. The function reads both secrets and builds a URL utility that appends these parameters automatically. The Trello API is notably permissive about the data you can request in a single call — the boards endpoint can return nested lists and cards in one request using the 'cards=all&lists=all' parameters, reducing the number of API round-trips needed.

The Edge Function below handles the most common Trello operations through an action-based router. Card creation accepts all standard Trello card fields — name, description, list ID, due date, member IDs, and label IDs. Card movement updates the idList field. The webhook action creates a Trello webhook subscription pointed at a callback URL (your deployed Edge Function) to receive real-time card movement events.

```
// supabase/functions/trello-proxy/index.ts
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";

const BASE = "https://api.trello.com";
const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
};

serve(async (req) => {
  if (req.method === "OPTIONS") {
    return new Response("ok", { headers: corsHeaders });
  }
  const key = Deno.env.get("TRELLO_API_KEY");
  const token = Deno.env.get("TRELLO_TOKEN");
  if (!key || !token) {
    return new Response(JSON.stringify({ error: "Trello credentials not configured" }), {
      status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" },
    });
  }

  const auth = `key=${key}&token=${token}`;
  const { action, params = {} } = await req.json();
  let resp;

  switch (action) {
    case "get_boards":
      resp = await fetch(`${BASE}/1/members/me/boards?fields=name,id,closed&filter=open&${auth}`);
      break;
    case "get_board":
      resp = await fetch(`${BASE}/1/boards/${params.boardId}?cards=all&lists=all&members=all&${auth}`);
      break;
    case "get_lists":
      resp = await fetch(`${BASE}/1/boards/${params.boardId}/lists?${auth}`);
      break;
    case "get_cards":
      resp = await fetch(`${BASE}/1/lists/${params.listId}/cards?members=true&labels=true&checklists=all&${auth}`);
      break;
    case "create_card": {
      const body = new URLSearchParams({
        idList: params.idList, name: params.name, desc: params.desc || "",
        ...(params.due && { due: params.due }),
        ...(params.idMembers && { idMembers: params.idMembers.join(",") }),
        ...(params.idLabels && { idLabels: params.idLabels.join(",") }),
      });
      resp = await fetch(`${BASE}/1/cards?${auth}`, { method: "POST", body, headers: { "Content-Type": "application/x-www-form-urlencoded" } });
      break;
    }
    case "update_card": {
      const body = new URLSearchParams(params.updates);
      resp = await fetch(`${BASE}/1/cards/${params.cardId}?${auth}`, { method: "PUT", body, headers: { "Content-Type": "application/x-www-form-urlencoded" } });
      break;
    }
    case "move_card":
      resp = await fetch(`${BASE}/1/cards/${params.cardId}?${auth}`, {
        method: "PUT",
        body: new URLSearchParams({ idList: params.idList }),
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
      });
      break;
    case "delete_card":
      resp = await fetch(`${BASE}/1/cards/${params.cardId}?${auth}`, { method: "DELETE" });
      break;
    case "create_webhook":
      resp = await fetch(`${BASE}/1/webhooks?${auth}`, {
        method: "POST",
        body: new URLSearchParams({ idModel: params.idModel, callbackURL: params.callbackURL, description: params.description || "Lovable Integration" }),
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
      });
      break;
    default:
      return new Response(JSON.stringify({ error: `Unknown action: ${action}` }), {
        status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" },
      });
  }

  const text = await resp.text();
  let data;
  try { data = JSON.parse(text); } catch { data = { raw: text }; }
  return new Response(JSON.stringify(data), {
    status: resp.status, headers: { ...corsHeaders, "Content-Type": "application/json" },
  });
});
```

**Expected result:** The Edge Function deploys. Calling action 'get_boards' returns your Trello boards. Calling 'get_board' with a board ID returns complete board data including nested lists and cards.

### 3. Build a custom kanban view in Lovable

With the Edge Function ready, you can build a custom kanban board that displays Trello data with a layout tailored to your app's design. A kanban board is fundamentally a set of columns (Trello lists) containing cards, and the Lovable React frontend can render this with full drag-and-drop card movement using libraries like @dnd-kit/core or react-beautiful-dnd.

The following prompt generates a complete kanban view component that fetches board data on mount, renders lists as columns, and uses optimistic UI updates when cards are dragged to new columns — the drag triggers immediately in the UI while the API call happens in the background, then reverts if the API call fails. This pattern gives users a snappy experience even with API latency.

**Expected result:** The kanban board renders all Trello lists as columns with their cards. Cards show labels, due dates, and member avatars. Dragging a card between columns updates Trello immediately via the Edge Function.

### 4. Configure Trello webhooks for real-time card tracking

Trello webhooks send real-time events to a callback URL when actions occur on a board or card — card created, card moved, card updated, checklist item completed, and many more. Setting up a webhook requires calling POST /1/webhooks with the board ID or card ID to watch (idModel), and your deployed Edge Function URL as the callbackURL.

Trello's webhook verification uses a different approach from most platforms: when you create a webhook, Trello sends a HEAD request to your callback URL to verify it's reachable. Your Edge Function must return a 200 response to HEAD requests to complete webhook registration. After registration, Trello sends POST requests for each event, including an action object with type, date, and data describing what changed. Common events to handle include 'updateCard' (card moved or modified), 'createCard', 'archiveCard', and 'updateCheckItemStateOnCard'.

**Expected result:** The webhook Edge Function responds to HEAD requests with 200, completing Trello's verification. Card movements on the board appear as events in your Supabase trello_events table within seconds.

## Best practices

- Use the 'get_board' endpoint with cards=all&lists=all for initial board loads rather than separate list and card requests — this reduces API calls from N+1 to a single request.
- Cache board list IDs in local state after the first fetch so drag-and-drop operations can reference them without re-fetching the board structure on every interaction.
- Implement optimistic UI updates for card moves — update the local state immediately, then send the API call in the background and revert if it fails, to ensure smooth drag-and-drop performance.
- Store label IDs in your app configuration so you can apply consistent labels (priority, category) without requiring users to look them up from the Trello API each time.
- Limit webhook subscriptions to specific boards rather than the entire account's boards — over-broad webhook subscriptions can flood your Edge Function with irrelevant events.
- Handle Trello's rate limit of 100 requests per 10 seconds by batching card fetches — the board endpoint with cards=all eliminates most pagination scenarios.
- Use card descriptions to store structured data (JSON-formatted metadata) when you need to track additional fields beyond Trello's native card properties — this data is fully accessible via the API.

## Use cases

### Custom kanban board with filtered card views

A product team uses Trello for feature tracking and wants a custom kanban view in their internal Lovable tool that shows only cards assigned to a specific member, filtered by label. The Edge Function fetches the board's lists and cards, and the frontend renders a drag-ready kanban column layout with card counts per list, due date highlighting, and member avatar display — providing a focused view not easily achievable in Trello's native filtering.

Prompt example:

```
Build a kanban view at /kanban that fetches all lists and cards from Trello board ID abc123def. Render each list as a column showing: list name, card count, and cards as draggable items. Each card should show: title, due date (red if overdue, orange if due today), assigned member avatars, and label colors. Add a filter bar at the top to filter cards by member or label. When a card is dragged to a new column, call my Trello Edge Function to update the card's list ID. Add a card count badge on each column header.
```

### Automated card creation from app events

A support team uses Trello to track open issues and wants new high-priority support tickets in their Lovable app to automatically create Trello cards in the 'New Issues' list with the ticket details pre-filled. When a ticket is created with priority 'Critical' in the app's Supabase database, a database trigger fires and an Edge Function creates a Trello card with the ticket title, description, and a red label for urgency.

Prompt example:

```
Set up automation so when a new row is inserted in the support_tickets table in Supabase with priority='critical', call my Trello Edge Function to create a card in list ID xyz789 with: name = ticket title, desc = ticket description + link to the ticket in my app, due date = 24 hours from now, and apply the red label with ID red-label-id. Add the card to the top of the list using pos: 'top'. Store the returned Trello card ID back in the support_tickets row.
```

### Team workflow status dashboard across multiple boards

An agency uses separate Trello boards for each client project and wants a single-screen status dashboard showing cards by stage across all active project boards. The Edge Function fetches the member's board list, then makes parallel requests to get card counts per list for each board, creating a cross-board summary showing work in flight, blocked items, and completed items per project.

Prompt example:

```
Build a status dashboard at /team-overview that fetches all Trello boards for my account. For each board, get the lists and count the cards in each list. Display boards as rows in a table with columns: Board Name (= project name), To Do count, In Progress count, Review count, Done count. Highlight boards where the 'In Progress' column has more than 5 cards (capacity warning). Click a board name to open a modal showing all cards in that board's 'In Progress' list with their due dates. Refresh every 5 minutes.
```

## Troubleshooting

### API returns 401 Unauthorized with 'invalid token' or 'invalid key'

Cause: Either the TRELLO_API_KEY or TRELLO_TOKEN secret is incorrect, the token has been revoked, or the token was generated with a different API key than the one being used.

Solution: In Trello, go to trello.com/app-key to view your API key. Verify it matches what's stored in TRELLO_API_KEY. For the token, it must have been generated using that exact API key — tokens are key-specific. If unsure, generate a new token using the authorize URL with your confirmed API key, update the TRELLO_TOKEN secret, and test again.

### Webhook registration fails with 'URL is not reachable' error

Cause: Trello sends a HEAD request to validate your webhook callback URL during registration. If the Edge Function URL is wrong, the app is not deployed, or the function doesn't handle HEAD requests, registration fails.

Solution: Ensure your webhook Edge Function handles HEAD requests by returning 200 before any other logic. Deploy the app first and use the deployed Edge Function URL (not the preview URL). Get the correct URL from Cloud → Logs after deploying. Test the URL independently with a HEAD request before registering the webhook.

```
if (req.method === "HEAD") {
  return new Response(null, { status: 200, headers: corsHeaders });
}
```

### Card move drag-and-drop succeeds in the UI but the move doesn't persist in Trello

Cause: The move_card action is being called with the wrong card ID or list ID, or the optimistic UI update is updating local state even when the API call fails silently.

Solution: Add error handling to your drag-end handler — if the move_card call returns an error status, revert the optimistic state update by moving the card back to its original list position. Log the exact cardId and idList values being sent to the Edge Function in Cloud → Logs to verify they are valid Trello IDs.

### Creating cards with idMembers or idLabels has no effect — the card is created without members or labels

Cause: When using form-encoded POST bodies (application/x-www-form-urlencoded), array values like idMembers must be comma-separated strings, not JSON arrays. Passing a JavaScript array directly results in '[object Array]' being sent instead of the actual IDs.

Solution: Join array values to comma-separated strings before sending: idMembers.join(',') and idLabels.join(',') rather than passing the raw arrays. Verify the comma-separated string is being appended correctly in the URLSearchParams.

```
const body = new URLSearchParams({
  idList: params.idList,
  name: params.name,
  idMembers: params.idMembers.join(","),
  idLabels: params.idLabels.join(","),
});
```

## Frequently asked questions

### Does Trello have a native connector in Lovable?

No, Trello is not one of Lovable's 17 shared connectors. Integration requires an Edge Function proxy using the Trello REST API v1. Store your API key and token in Cloud Secrets and route all calls through the server-side function — the Trello credentials are never exposed to browser code.

### What is the difference between a Trello API key and a token?

The API key identifies your application and is tied to your Trello Power-Up developer app — it's static and doesn't change. The token authorizes a specific user's data access and is generated per-user through the OAuth-like authorization URL. For server-side integrations where you're accessing your own Trello data, generate a single long-lived token using expiration=never in the authorization URL.

### Can I implement drag-and-drop card movement between lists?

Yes — the move_card action updates a card's idList field via PUT /1/cards/{cardId}. For smooth drag-and-drop UX, use an optimistic update pattern: update local state immediately when the drag ends, then call the Edge Function in the background. If the API call fails, revert the state. Libraries like @dnd-kit/core work well with Lovable's React/Tailwind setup for implementing the drag behavior.

### How do I get Trello Power-Up custom fields through the API?

Trello custom fields are created by the Custom Fields Power-Up. To include them in API responses, add customFieldItems=true to your card request parameters. Each card then includes a customFieldItems array where each entry has a value object and an idCustomField reference. You'll also need to fetch the board's customFields definitions separately (GET /1/boards/{boardId}/customFields) to get field names and types to display them correctly.

### Is there a way to filter board cards by label or member in the API?

The Trello API doesn't support server-side filtering for standard card list endpoints — all cards are returned and filtering must happen client-side. Fetch all cards for a list or board and filter the results in your Edge Function or frontend before rendering. For large boards with hundreds of cards, implement client-side filtering in React state to keep the UI responsive without additional API calls.

---

Source: https://www.rapidevelopers.com/lovable-integration/trello
© RapidDev — https://www.rapidevelopers.com/lovable-integration/trello
