# Create RSS/Podcast Feed

## User Intent

"I want to sync RSS feeds or podcast episodes into Graphlit for search and AI interactions"

## Operation

* **SDK Method**: `graphlit.createFeed()` with RSS configuration
* **GraphQL**: `createFeed` mutation
* **Entity Type**: Feed
* **Common Use Cases**: RSS feed monitoring, podcast ingestion, news aggregation, blog sync

## TypeScript (Canonical)

```typescript
import { Graphlit } from 'graphlit-client';
import { ContentTypes, FeedTypes } from 'graphlit-client/dist/generated/graphql-types';

const graphlit = new Graphlit();

const response = await graphlit.createFeed({
  name: 'Tech News RSS',
  type: FeedTypes.Rss,
  rss: {
    uri: 'https://news.example.com/rss.xml',
    readLimit: 100,
  },
});

const feedId = response.createFeed.id;
console.log(`RSS feed created: ${feedId}`);

while (true) {
  const status = await graphlit.isFeedDone(feedId);
  if (status.isFeedDone.result) {
    break;
  }

  console.log('Still syncing RSS items...');
  await new Promise((resolve) => setTimeout(resolve, 10_000));
}

console.log('RSS feed sync complete!');

const items = await graphlit.queryContents({
  feeds: [{ id: feedId }],
  types: [ContentTypes.Page],
});

console.log(`Synced ${items.contents.results.length} RSS items`);
```

## Parameters

### FeedInput (Required)

* **`name`** (string): Feed name
* **`type`** (FeedTypes): Must be `RSS`
* **`rss`** (RSSFeedPropertiesInput): RSS configuration

### RSSFeedPropertiesInput (Required)

* **`uri`** (string): RSS feed URL
  * Must be valid RSS/Atom XML feed
  * Works with podcast feeds (audio files auto-downloaded)
* **`readLimit`** (int): Max items to sync
  * Limits initial sync
  * Continuous monitoring after initial sync

### Optional

* **`correlationId`** (string): For tracking
* **`collections`** (EntityReferenceInput\[]): Auto-add items to collections
* **`workflow`** (EntityReferenceInput): Apply workflow to items

## Response

```typescript
{
  createFeed: {
    id: string;              // Feed ID
    name: string;            // Feed name
    state: EntityState;      // ENABLED
    type: FeedTypes.Rss;     // RSS
    rss: {
      uri: string;           // Feed URL
      readLimit: number;     // Item limit
    }
  }
}
```

## Developer Hints

### RSS vs Podcast Feeds

**Both use same API**:

```typescript
// News RSS feed
const newsFeed = {
  type: FeedTypes.Rss,
  rss: {
    uri: 'https://news.site.com/rss.xml',
    readLimit: 50
  }
};

// Podcast feed (same structure)
const podcastFeed = {
  type: FeedTypes.Rss,
  rss: {
    uri: 'https://podcast.example.com/feed.xml',
    readLimit: 20  // Episodes
  }
};
```

**Important**: Podcast audio files are automatically downloaded and transcribed if you have a preparation workflow.

### Read Limit Strategy

```typescript
// Initial backfill (large limit)
const backfillFeed = {
  rss: {
    uri: rssUrl,
    readLimit: 1000  // Get historical items
  }
};

// Ongoing monitoring (small limit)
const monitoringFeed = {
  rss: {
    uri: rssUrl,
    readLimit: 10  // Just recent items
  }
};
```

**Important**: After initial sync, feed continuously monitors for new items regardless of `readLimit`.

### Content Type for RSS Items

```typescript
// RSS items typically come in as Page type
const rssItems = await graphlit.queryContents({
  feeds: [{ id: feedId }],
  types: [ContentTypes.Page]
});

// Podcast audio files come as File type
const podcastEpisodes = await graphlit.queryContents({
  feeds: [{ id: podcastFeedId }],
  types: [ContentTypes.File],
  fileTypes: [FileTypes.Audio]
});
```

### Podcast Transcription

```typescript
// Create workflow for podcast transcription
const workflow = await graphlit.createWorkflow({
  name: 'Podcast Transcription',
  preparation: {
    jobs: [{
      connector: {
        type: FilePreparationServiceTypes.Deepgram,
        deepgram: {
          model: DeepgramModels.Nova2
        }
      }
    }]
  }
});

// Create podcast feed with workflow
const podcastFeed = await graphlit.createFeed({
  name: 'Tech Podcast',
  type: FeedTypes.Rss,
  rss: {
    uri: 'https://podcast.example.com/feed.xml',
    readLimit: 50
  },
  workflow: { id: workflow.createWorkflow.id }
});

// Episodes automatically transcribed
```

## Variations

### 1. Basic RSS Feed

Simplest RSS sync:

```typescript
const feed = await graphlit.createFeed({
  name: 'News Feed',
  type: FeedTypes.Rss,
  rss: {
    uri: 'https://news.example.com/rss',
    readLimit: 100
  }
});
```

### 2. Podcast Feed with Transcription

Podcast with audio transcription:

```typescript
// Create transcription workflow
const workflow = await graphlit.createWorkflow({
  name: 'Transcribe Podcasts',
  preparation: {
    jobs: [{
      connector: {
        type: FilePreparationServiceTypes.Deepgram,
        deepgram: {
          model: DeepgramModels.Nova2
        }
      }
    }]
  }
});

// Create podcast feed
const feed = await graphlit.createFeed({
  name: 'My Podcast',
  type: FeedTypes.Rss,
  rss: {
    uri: 'https://podcast.example.com/feed.xml',
    readLimit: 20
  },
  workflow: { id: workflow.createWorkflow.id }
});
```

### 3. RSS with Auto-Collection

Add items to collection:

```typescript
// Create collection
const collection = await graphlit.createCollection({
  name: 'RSS Articles'
});

// Create feed
const feed = await graphlit.createFeed({
  name: 'Tech News',
  type: FeedTypes.Rss,
  rss: {
    uri: 'https://technews.com/rss',
    readLimit: 100
  },
  collections: [{ id: collection.createCollection.id }]
});
```

### 4. Multiple RSS Feeds

Aggregate multiple sources:

```typescript
const rssSources = [
  { name: 'TechCrunch', url: 'https://techcrunch.com/feed/' },
  { name: 'Hacker News', url: 'https://news.ycombinator.com/rss' },
  { name: 'The Verge', url: 'https://theverge.com/rss' }
];

// Create collection for all tech news
const collection = await graphlit.createCollection({
  name: 'Tech News Aggregator'
});

// Create feed for each source
for (const source of rssSources) {
  await graphlit.createFeed({
    name: source.name,
    type: FeedTypes.Rss,
    rss: {
      uri: source.url,
      readLimit: 50
    },
    collections: [{ id: collection.createCollection.id }]
  });
}

// Now query all tech news from one collection
const allNews = await graphlit.queryContents({
  collections: [{ id: collection.createCollection.id }],
  orderBy: OrderByTypes.CreationDate,
  direction: OrderDirectionTypes.Descending
});
```

### 5. RSS with Entity Extraction

Extract people, companies from articles:

```typescript
// Create extraction workflow
const workflow = await graphlit.createWorkflow({
  name: 'Extract Entities',
  extraction: {
    jobs: [{
      connector: {
        type: EntityExtractionServiceTypes.ModelText,
        modelText: {
          specification: { id: extractionSpecId },
          observables: [
            ObservableTypes.Person,
            ObservableTypes.Organization,
            ObservableTypes.Label
          ]
        }
      }
    }]
  }
});

// Create RSS feed with extraction
const feed = await graphlit.createFeed({
  name: 'Business News',
  type: FeedTypes.Rss,
  rss: {
    uri: 'https://businessnews.com/rss',
    readLimit: 100
  },
  workflow: { id: workflow.createWorkflow.id }
});

// Query extracted entities from news
const entities = await graphlit.queryObservables({
  contents: [{ feedId: feed.createFeed.id }],
  observableTypes: [ObservableTypes.Organization]
});
```

### 6. Limited Backfill Feed

Only recent items:

```typescript
const feed = await graphlit.createFeed({
  name: 'Recent News Only',
  type: FeedTypes.Rss,
  rss: {
    uri: 'https://news.example.com/rss',
    readLimit: 10  // Just 10 most recent
  }
});

// Still monitors for new items going forward
```

## Common Issues

**Issue**: `Invalid RSS feed` error\
**Solution**: Verify RSS URL returns valid XML. Test URL in browser. Some sites require User-Agent header.

**Issue**: No items syncing\
**Solution**: Check `readLimit` is set. Verify RSS feed has items. Some feeds may be empty.

**Issue**: Podcast audio not transcribed\
**Solution**: Ensure preparation workflow is attached to feed. Check workflow has audio transcription configured.

**Issue**: Feed syncs old items only\
**Solution**: This is initial backfill. After initial sync, feed monitors for new items automatically.

**Issue**: Duplicate items appearing\
**Solution**: Graphlit deduplicates by item GUID. If feed doesn't have unique GUIDs, duplicates may occur.

## Production Example

**News aggregation pipeline**:

```typescript
// 1. Create collection for all news
const newsCollection = await graphlit.createCollection({
  name: 'Tech News'
});

// 2. Create extraction workflow
const workflow = await graphlit.createWorkflow({
  name: 'News Extraction',
  extraction: {
    jobs: [{
      connector: {
        type: EntityExtractionServiceTypes.ModelText,
        modelText: {
          specification: { id: extractionSpecId }
        }
      }
    }]
  }
});

// 3. Create RSS feeds
const feeds = [
  'https://techcrunch.com/feed/',
  'https://theverge.com/rss',
  'https://arstechnica.com/feed/'
];

for (const feedUrl of feeds) {
  const feed = await graphlit.createFeed({
    name: `RSS: ${feedUrl}`,
    type: FeedTypes.Rss,
    rss: {
      uri: feedUrl,
      readLimit: 50
    },
    collections: [{ id: newsCollection.createCollection.id }],
    workflow: { id: workflow.createWorkflow.id }
  });
  
  console.log(`Created feed: ${feed.createFeed.id}`);
}

// 4. Query aggregated news
const latestNews = await graphlit.queryContents({
  collections: [{ id: newsCollection.createCollection.id }],
  orderBy: OrderByTypes.CreationDate,
  direction: OrderDirectionTypes.Descending,
  limit: 20
});

console.log(`\nLatest ${latestNews.contents.results.length} articles:`);
latestNews.contents.results.forEach(article => {
  console.log(`- ${article.name}`);
});
```

**Podcast monitoring system**:

```typescript
// 1. Create transcription workflow
const workflow = await graphlit.createWorkflow({
  name: 'Podcast Transcription',
  preparation: {
    jobs: [{
      connector: {
        type: FilePreparationServiceTypes.Deepgram,
        deepgram: {
          model: DeepgramModels.Nova2,
          enableSpeakerDiarization: true
        }
      }
    }]
  }
});

// 2. Create podcast feeds
const podcasts = [
  { name: 'Tech Podcast A', url: 'https://podcast-a.com/feed.xml' },
  { name: 'Business Podcast B', url: 'https://podcast-b.com/feed.xml' }
];

for (const podcast of podcasts) {
  const feed = await graphlit.createFeed({
    name: podcast.name,
    type: FeedTypes.Rss,
    rss: {
      uri: podcast.url,
      readLimit: 20  // Last 20 episodes
    },
    workflow: { id: workflow.createWorkflow.id }
  });
  
  // Wait for initial sync
  await waitForFeedCompletion(feed.createFeed.id);
  
  console.log(` ${podcast.name} synced and transcribed`);
}

// 3. Search transcripts
const results = await graphlit.queryContents({
  search: 'artificial intelligence',
  searchType: SearchTypes.Hybrid,
  types: [ContentTypes.File],
  fileTypes: [FileTypes.Audio]
});

console.log(`\nFound ${results.contents.results.length} episodes mentioning AI`);
```


---

# Agent Instructions: Querying This Documentation

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

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.graphlit.dev/api-guides/use-cases/feeds/web/feed-create-rss.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
