List Fireflies Meetings
Fetch recent meetings with metadata from Fireflies.ai
Source Code
import fs from "fs";
import path from "path";
const [outputPath, limit, keyword, fromDate] = process.argv.slice(2);
if (!outputPath) {
console.error("Error: outputPath is required");
console.error("Usage: node script.js session/meetings.json [limit] [keyword] [fromDate]");
process.exit(1);
}
const limitNum = limit ? Math.min(parseInt(limit, 10) || 20, 50) : 20;
console.log("Fetching meetings from Fireflies...");
if (keyword) console.log(` Search: "${keyword}"`);
if (fromDate) console.log(` From: ${fromDate}`);
try {
// Build GraphQL query
const query = `
query Transcripts($limit: Int, $keyword: String, $fromDate: DateTime) {
transcripts(limit: $limit, keyword: $keyword, fromDate: $fromDate) {
id
title
date
duration
participants
organizer_email
transcript_url
speakers {
id
name
}
summary {
gist
short_summary
action_items
}
}
}
`;
const variables = { limit: limitNum };
if (keyword) variables.keyword = keyword;
if (fromDate) variables.fromDate = fromDate;
const res = await fetch("https://api.fireflies.ai/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer PLACEHOLDER_TOKEN",
},
body: JSON.stringify({ query, variables }),
});
const data = await res.json();
if (data.errors) {
const errMsg = data.errors[0]?.message || "GraphQL error";
throw new Error(`Fireflies API: ${errMsg}`);
}
const transcripts = data.data?.transcripts || [];
console.log(` Found ${transcripts.length} meetings`);
// Process meetings for readable output
const meetings = transcripts.map((t) => {
// Convert epoch ms to ISO string
const dateISO = t.date ? new Date(t.date).toISOString() : null;
const dateFormatted = t.date
? new Date(t.date).toLocaleDateString("en-US", {
weekday: "short",
month: "short",
day: "numeric",
})
: null;
return {
id: t.id,
title: t.title || "(Untitled meeting)",
date: dateISO,
dateFormatted,
durationMinutes: t.duration || null,
participants: t.participants || [],
participantCount: (t.participants || []).length,
organizer: t.organizer_email || null,
speakers: (t.speakers || []).map((s) => s.name).filter(Boolean),
speakerCount: (t.speakers || []).length,
gist: t.summary?.gist || null,
shortSummary: t.summary?.short_summary || null,
actionItems: t.summary?.action_items || null,
transcriptUrl: t.transcript_url || null,
};
});
// Sort by date (newest first)
meetings.sort((a, b) => new Date(b.date) - new Date(a.date));
// Build output
const output = {
query: {
limit: limitNum,
keyword: keyword || null,
fromDate: fromDate || null,
},
summary: {
totalMeetings: meetings.length,
},
meetings,
};
// Write output
const dir = path.dirname(outputPath);
if (dir && dir !== ".") fs.mkdirSync(dir, { recursive: true });
fs.writeFileSync(outputPath, JSON.stringify(output, null, 2));
console.log(`\nā Found ${meetings.length} meetings`);
console.log(` Output: ${outputPath}`);
// Show preview
if (meetings.length > 0) {
console.log(`\n Recent meetings:`);
meetings.slice(0, 5).forEach((m) => {
const duration = m.durationMinutes ? `${m.durationMinutes} min` : "";
const speakers = m.speakerCount > 0 ? `${m.speakerCount} speakers` : "";
const meta = [duration, speakers].filter(Boolean).join(", ");
console.log(` ${m.dateFormatted} - ${m.title}${meta ? ` (${meta})` : ""}`);
});
if (meetings.length > 5) {
console.log(` ... and ${meetings.length - 5} more`);
}
}
console.log(
JSON.stringify({
success: true,
outputPath,
meetingCount: meetings.length,
})
);
} catch (error) {
console.error("Failed:", error.message);
throw error;
}