This guide provides comprehensive documentation for all configuration options in the Crypto Twitter Alpha Stream application.
- Configuration Methods
- Configuration Priority
- Required Configuration
- Migration from SSE to WebSocket
- Environment Variables
- JSON Configuration File
- Configuration Examples
- Advanced Configuration
- Best Practices
The application supports three configuration methods:
- Environment Variables - Set via
.envfile or system environment - JSON Configuration File -
config/config.json - Default Values - Built-in fallback values
When the same setting is defined in multiple places, the following priority order applies:
Environment Variables > config.json > Default Values
Example: If DASHBOARD_PORT is set to 4000 in .env and 3000 in config.json, the application will use 4000.
Two configuration values are required:
Your Apify API authentication token.
Required: Yes
Type: String
Source: Environment variable only (for security)
Example: APIFY_TOKEN=apify_api_AbCdEfGhIjKlMnOpQrStUvWxYz
How to get your token:
- Log in to Apify Console
- Navigate to Settings → Integrations (or use the direct link above)
- Copy your API token
Security Note: Never commit your token to version control. Always use environment variables.
The URL of the deployed Apify Standby Actor.
Required: Yes
Type: String (URL)
Source: Environment variable
Example: APIFY_ACTOR_URL=https://muhammetakkurtt--crypto-twitter-tracker.apify.actor
The base URL of the crypto-twitter-tracker actor that provides the WebSocket stream. Supports http/https/ws/wss formats - automatically converted to the appropriate protocol.
Important: This configuration is mandatory. The application will fail to start without it.
The application has migrated from Server-Sent Events (SSE) to WebSocket (WSS) for improved real-time communication. This section helps you migrate your configuration.
Protocol: SSE → WebSocket
- Old: Unidirectional HTTP-based streaming
- New: Bidirectional WebSocket connection with subscribe protocol
Configuration:
ENDPOINT→CHANNELS(now supports multiple channels)- URL format now supports ws/wss in addition to http/https
Connection Flow:
- Old: HTTP GET request to SSE endpoint
- New: WebSocket connection + subscribe message
-
Update Environment Variable:
# Old (SSE) ENDPOINT=all # New (WebSocket) CHANNELS=all
-
Multiple Channels (new feature):
# You can now subscribe to multiple channels CHANNELS=tweets,following
-
URL Format (optional):
# All formats work - automatically converted APIFY_ACTOR_URL=https://muhammetakkurtt--crypto-twitter-tracker.apify.actor # Converted to wss:// APIFY_ACTOR_URL=wss://muhammetakkurtt--crypto-twitter-tracker.apify.actor # Used as-is
-
Update config.json (if using):
{ "apify": { "channels": ["all"] // Changed from "endpoint": "all" } }
The migration maintains backward compatibility for all user-facing behavior:
- Event format remains unchanged
- Filtering works identically
- Output channels work identically
- All configuration options (except ENDPOINT→CHANNELS) remain the same
Multiple Channel Subscription:
# Subscribe to multiple event types simultaneously
CHANNELS=tweets,following,profileImproved Reconnection:
- WebSocket protocol-level ping/pong for connection health
- Automatic reconnection with exponential backoff
- Graceful shutdown handling (5 second delay before reconnect)
URL Flexibility:
- Accepts http/https/ws/wss formats
- Automatically converts to appropriate protocol
- Same base URL works for WebSocket and REST endpoints
Problem: "ENDPOINT environment variable not recognized"
Solution: Change ENDPOINT to CHANNELS in your .env file
Problem: "Invalid channels configuration"
Solution: Ensure channels is comma-separated: CHANNELS=tweets,following
Problem: "Connection fails with new configuration"
Solution:
- Verify your token is still valid
- Check that the actor URL is correct
- Try with
CHANNELS=allfirst to test connection
The application automatically normalizes channel configurations to align with the tracker server's protocol semantics. This ensures consistent behavior between client and server.
-
Empty Channels Array: When no channels are specified (empty array), the application normalizes it to
["all"]# These are equivalent: CHANNELS= CHANNELS=all
-
"all" Channel Dominance: When "all" is present with other channels, the application normalizes to
["all"]only# These are all equivalent: CHANNELS=all CHANNELS=all,tweets CHANNELS=tweets,all,following # All normalize to: ["all"]
-
Multiple Specific Channels: When multiple specific channels are provided without "all", they remain unchanged
CHANNELS=tweets,following # Remains: ["tweets", "following"]
The tracker server treats "all" as a special channel that includes all event types. When "all" is present, subscribing to additional specific channels is redundant. The normalization ensures:
- Protocol Alignment: Client behavior matches server semantics
- Efficiency: Avoids redundant subscriptions
- Clarity: Makes the actual subscription explicit
| Configuration | Normalized To | Explanation |
|---|---|---|
CHANNELS= |
["all"] |
Empty defaults to all events |
CHANNELS=all |
["all"] |
Already normalized |
CHANNELS=tweets |
["tweets"] |
Single specific channel |
CHANNELS=tweets,following |
["tweets", "following"] |
Multiple specific channels |
CHANNELS=all,tweets |
["all"] |
"all" dominates |
CHANNELS=tweets,all,profile |
["all"] |
"all" dominates |
The application validates channels configuration during startup:
- Empty array: Accepted (normalizes to
["all"]) - Valid channels: Accepted (normalized if needed)
- Invalid channels: Rejected with error message
Example Startup Log:
✓ Configuration validated successfully
Channels: ["all"] (normalized from ["all", "tweets"])
-
Use "all" for comprehensive monitoring: If you want all event types, just use
CHANNELS=all -
Use specific channels for targeted monitoring: If you only need tweets, use
CHANNELS=tweets -
Don't mix "all" with specific channels: The application will normalize it to
["all"]anyway -
Leave empty for default behavior: Empty channels configuration defaults to
["all"]
All environment variables can be set in a .env file in the project root. See .env.example for a complete template.
Required: Yes
Type: String
Default: None
Example: APIFY_TOKEN=apify_api_AbCdEfGhIjKlMnOpQrStUvWxYz
Your Apify API token for authentication.
Required: Yes
Type: String (URL)
Source: Environment variable
Example: APIFY_ACTOR_URL=https://muhammetakkurtt--crypto-twitter-tracker.apify.actor
The base URL of the deployed Apify Standby Actor that provides the WebSocket stream. Supports http/https/ws/wss formats - automatically converted to the appropriate protocol.
Important: This configuration is mandatory. The application will fail to start without it.
URL Format Flexibility:
http://host→ Converted tows://hostfor WebSockethttps://host→ Converted towss://hostfor WebSocketws://host→ Used as-is for WebSocketwss://host→ Used as-is for WebSocket
Actor Page: https://apify.com/muhammetakkurtt/crypto-twitter-tracker?fpr=muh
The application automatically handles protocol conversion between HTTP/HTTPS and WebSocket (WS/WSS) protocols. This allows you to use any URL format, and the application will convert it to the appropriate protocol for each use case.
How It Works:
-
WebSocket Connections: The application converts HTTP/HTTPS URLs to WS/WSS for WebSocket connections
http://host→ws://host(WebSocket connection)https://host→wss://host(WebSocket connection)ws://host→ws://host(used as-is)wss://host→wss://host(used as-is)
-
REST Endpoints: The application converts WS/WSS URLs to HTTP/HTTPS for REST API calls (like
/active-users)ws://host→http://host(REST endpoint)wss://host→https://host(REST endpoint)http://host→http://host(used as-is)https://host→https://host(used as-is)
Protocol Selection for REST Endpoints:
When making HTTP requests to REST endpoints (like /active-users), the application automatically selects the correct HTTP client based on the converted URL protocol:
- HTTP URLs (
http://): Uses Node.jshttpmodule - HTTPS URLs (
https://): Uses Node.jshttpsmodule
This ensures that both HTTP and HTTPS endpoints work correctly without manual configuration.
Examples:
| Base URL Configuration | WebSocket Connection | REST Endpoint | HTTP Client |
|---|---|---|---|
http://localhost:8080 |
ws://localhost:8080 |
http://localhost:8080/active-users |
http |
https://example.com |
wss://example.com |
https://example.com/active-users |
https |
ws://localhost:8080 |
ws://localhost:8080 |
http://localhost:8080/active-users |
http |
wss://example.com |
wss://example.com |
https://example.com/active-users |
https |
Why This Matters:
- Flexibility: You can use any URL format in your configuration
- Consistency: The same base URL works for both WebSocket and REST endpoints
- Security: HTTPS/WSS URLs automatically use secure connections
- Development: Use
http://localhostfor local development without SSL certificates - Production: Use
https://URLs for production deployments with SSL
Configuration Examples:
# Local development (HTTP)
APIFY_ACTOR_URL=http://localhost:8080
# Production (HTTPS)
APIFY_ACTOR_URL=https://muhammetakkurtt--crypto-twitter-tracker.apify.actor
# Explicit WebSocket (WS)
APIFY_ACTOR_URL=ws://localhost:8080
# Explicit WebSocket Secure (WSS)
APIFY_ACTOR_URL=wss://muhammetakkurtt--crypto-twitter-tracker.apify.actorAll of these configurations work correctly - the application handles protocol conversion automatically.
Required: No
Type: Comma-separated string
Default: all
Options: all, tweets, following, profile
Example: CHANNELS=tweets,following
Selects which channels to subscribe to via WebSocket. You can subscribe to multiple channels simultaneously.
Available Channels:
all- All Twitter events (posts, profile updates, following changes)tweets- Only new tweet/post eventsfollowing- Only following/unfollowing eventsprofile- Only profile update events
Multiple Channels: Specify multiple channels separated by commas:
CHANNELS=tweets,followingThis will subscribe to both tweets and following events simultaneously.
Required: No
Type: Comma-separated string
Default: Empty (all users)
Example: USERS=elonmusk,vitalikbuterin,cz_binance
Filter events to only include specific Twitter usernames. This enables both actor-side and client-side filtering for cost optimization.
How It Works - Two-Layer Filtering:
-
Actor-Side Filtering (Layer 1): When you configure
USERS, the application includes them in the WebSocket subscribe message. The actor filters events at the source and only delivers events from your specified users. This significantly reduces costs because you're only charged for events actually delivered to your client. -
Client-Side Filtering (Layer 2): After events are received, the application applies additional client-side filters (if configured). This provides extra refinement but doesn't affect costs since events are already delivered.
Cost Implications:
The Apify actor charges per event per client. User filtering allows you to control which events are delivered to your client. Without user filtering, you receive events from all monitored accounts. With user filtering, you only receive events from your specified users, which can reduce the number of events delivered.
Examples:
- No filter: Receives events from all monitored accounts
- 3 users: Receives events only from those 3 accounts
- 10 users: Receives events only from those 10 accounts
Important: Before configuring user filters, check the monitored users list for reference:
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://muhammetakkurtt--crypto-twitter-tracker.apify.actor/active-usersNote: The actor may monitor additional users beyond the returned list.
Format Rules:
- Comma-separated, no spaces
- Case-insensitive
- No @ symbol
- Usernames only (not display names)
- Can include usernames not in the returned list (actor may still monitor them)
Validation: The application validates configured usernames on startup and provides advisory warnings for usernames not in the returned list. These warnings are informational - the actor may still monitor those users.
Required: No
Type: Comma-separated string
Default: Empty (all content)
Example: KEYWORDS=bitcoin,ethereum,crypto,defi
Filter events to only include those containing specific keywords. Leave empty to receive all events regardless of content.
Format Rules:
- Comma-separated, no spaces
- Case-insensitive matching
- Searches in tweet text and profile fields
- Partial word matching (e.g., "crypto" matches "cryptocurrency")
The application uses a two-layer filtering system that combines actor-side and client-side filtering for optimal cost efficiency and flexibility.
When you configure the USERS environment variable, the application includes them in the WebSocket subscribe message. The actor filters events at the source before delivering them to your client.
Benefits:
- Reduces network traffic (fewer events transmitted)
- Reduces the number of events you're charged for
- Reduces processing load (fewer events to handle)
How it works:
User Config: USERS=elonmusk,vitalikbuterin
↓
Application connects via WebSocket
↓
Application sends subscribe message: {"op":"subscribe","channels":["all"],"users":["elonmusk","vitalikbuterin"]}
↓
Actor filters at source: Only sends elonmusk and vitalikbuterin events
↓
Client receives: ONLY filtered events
↓
Charged for: Only the 2 accounts' events ✅
After events are received from the actor, the application applies additional filters based on KEYWORDS and event types. This happens in the FilterPipeline component.
Benefits:
- Additional refinement of received events
- Flexible filtering by keywords and event types
- Applied after events are delivered
How it works:
Events received from actor (already filtered by users)
↓
FilterPipeline applies keyword filters
↓
FilterPipeline applies event type filters
↓
Filtered events sent to output channels
Configuration:
USERS=elonmusk,vitalikbuterin,cz_binance
KEYWORDS=bitcoin,ethereumFlow:
-
Actor-Side (Layer 1): Actor only sends events from elonmusk, vitalikbuterin, and cz_binance
- Only these 3 accounts' events are delivered
-
Client-Side (Layer 2): Application filters for keywords "bitcoin" or "ethereum"
- Further filters the received events by keywords
Result: You receive events from 3 accounts, filtered by keywords.
| Aspect | Actor-Side (USERS) | Client-Side (KEYWORDS) |
|---|---|---|
| Where | At the actor (source) | In the application |
| Network Traffic | Reduces traffic ✅ | No traffic impact |
| Filters By | Twitter usernames | Keywords, event types |
| Configuration | USERS env variable | KEYWORDS env variable |
| Validation | Validated on startup | No validation needed |
-
Use actor-side filtering to control event volume: Configure
USERSif you only need specific accounts. This reduces the number of events delivered to your client. -
Use client-side filtering for refinement: Use
KEYWORDSto further filter events after they're received. This is useful for finding specific topics. -
Combine both layers: Use
USERSto select accounts andKEYWORDSto refine results:USERS=elonmusk,vitalikbuterin,cz_binance # Select accounts KEYWORDS=bitcoin,ethereum,defi # Refine by keywords
-
Check monitored users for reference: Before configuring
USERS, you can check the monitored users list for reference:curl -H "Authorization: Bearer YOUR_TOKEN" \ https://muhammetakkurtt--crypto-twitter-tracker.apify.actor/active-usersNote: The actor may monitor additional users beyond this list.
Required: No
Type: Boolean
Default: true
Example: CLI_ENABLED=true
Enable or disable CLI output (live stream in terminal).
Required: No
Type: Number (milliseconds)
Default: 60000 (1 minute)
Example: CLI_STATS_INTERVAL=30000
Interval between statistics displays in CLI output.
Required: No
Type: Boolean
Default: true
Example: DASHBOARD_ENABLED=true
Enable or disable the web dashboard.
Required: No
Type: Number
Default: 3000
Example: DASHBOARD_PORT=8080
Port for the web dashboard server. The dashboard will be accessible at http://localhost:{PORT}.
Required: No
Type: Boolean
Default: false
Example: TELEGRAM_ENABLED=true
Enable or disable Telegram alerts.
Required: If Telegram is enabled
Type: String
Default: None
Example: TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrsTUVwxyz
Telegram bot token from @BotFather.
How to get a bot token:
- Message @BotFather on Telegram
- Send
/newbotcommand - Follow the prompts to create your bot
- Copy the token provided
Required: If Telegram is enabled
Type: String
Default: None
Example: TELEGRAM_CHAT_ID=123456789
Telegram chat ID where alerts will be sent.
How to get your chat ID:
- Message @userinfobot on Telegram
- Copy the ID provided
- Alternatively, add your bot to a group and use the group's chat ID
Required: No
Type: Boolean
Default: false
Example: DISCORD_ENABLED=true
Enable or disable Discord alerts.
Required: If Discord is enabled
Type: String (URL)
Default: None
Example: DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/123456789/abcdefg
Discord webhook URL for sending alerts.
How to create a webhook:
- Open your Discord server settings
- Go to Integrations → Webhooks
- Click "New Webhook"
- Configure the webhook (name, channel)
- Copy the webhook URL
Required: No
Type: Boolean
Default: false
Example: WEBHOOK_ENABLED=true
Enable or disable generic webhook alerts.
Required: If webhook is enabled
Type: String (URL)
Default: None
Example: WEBHOOK_URL=https://your-webhook-url.com/endpoint
Generic webhook URL for POST requests. The application will POST JSON event data to this URL.
Webhook Payload Format:
{
"type": "post_created",
"timestamp": "2024-01-15T14:30:22.000Z",
"user": {
"username": "elonmusk",
"displayName": "Elon Musk"
},
"data": { ... }
}Required: No
Type: Number
Default: 3001
Example: HEALTH_PORT=8081
Port for the health monitoring HTTP server. The /status endpoint will be available at http://localhost:{PORT}/status.
Required: No
Type: Number (seconds)
Default: 60
Example: DEDUP_TTL=120
Time-to-live for deduplication cache entries. Events are cached for this duration to prevent duplicates.
Recommendations:
- Lower values (30-60s) for high-volume streams
- Higher values (120-300s) for low-volume streams or if duplicates are common
Required: No
Type: Number (milliseconds)
Default: 1000
Example: RECONNECT_INITIAL_DELAY=2000
Initial delay before the first reconnection attempt after a connection failure.
Required: No
Type: Number (milliseconds)
Default: 30000
Example: RECONNECT_MAX_DELAY=60000
Maximum delay between reconnection attempts. The delay increases exponentially but never exceeds this value.
Required: No
Type: Number
Default: 2.0
Example: RECONNECT_BACKOFF_MULTIPLIER=1.5
Multiplier for exponential backoff. Each reconnection attempt waits previousDelay * multiplier milliseconds.
Formula: delay = min(initialDelay * multiplier^attempt, maxDelay)
Required: No
Type: Number
Default: 0 (infinite)
Example: RECONNECT_MAX_ATTEMPTS=10
Maximum number of reconnection attempts. Set to 0 for infinite retries.
Required: No
Type: Number (milliseconds)
Default: 240000 (4 minutes)
Example: ACTIVE_USERS_REFRESH_INTERVAL=600000
Interval for refreshing the active users list from the Apify actor.
Required: No
Type: Number
Default: 10
Example: ALERT_RATE_LIMIT=20
Maximum number of alerts per minute per channel. Excess alerts are dropped.
Configuration can also be provided via config/config.json. This is useful for:
- Committing non-sensitive configuration to version control
- Sharing configuration across team members
- Managing multiple configuration profiles
config/config.json (relative to project root)
{
"apify": {
"channels": ["all"] | ["tweets"] | ["following"] | ["profile"] | ["tweets", "following"]
},
"filters": {
"users": ["username1", "username2"],
"keywords": ["keyword1", "keyword2"]
},
"outputs": {
"cli": {
"enabled": true,
"statsInterval": 60000
},
"dashboard": {
"enabled": true,
"port": 3000
},
"alerts": {
"telegram": {
"enabled": false
},
"discord": {
"enabled": false
},
"webhook": {
"enabled": false
}
}
},
"dedup": {
"ttl": 60
},
"reconnect": {
"initialDelay": 1000,
"maxDelay": 30000,
"backoffMultiplier": 2.0,
"maxAttempts": 0
},
"activeUsers": {
"refreshInterval": 240000
},
"health": {
"port": 3001
}
}See config/config.example.json for a complete example.
Note: Sensitive values like APIFY_TOKEN, TELEGRAM_BOT_TOKEN, etc. should never be stored in config.json. Always use environment variables for secrets.
Minimal configuration for CLI output only.
.env:
APIFY_TOKEN=your_token_here
APIFY_ACTOR_URL=https://muhammetakkurtt--crypto-twitter-tracker.apify.actor
CHANNELS=all
DASHBOARD_ENABLED=falseMonitor specific users and keywords with web dashboard.
.env:
APIFY_TOKEN=your_token_here
APIFY_ACTOR_URL=https://muhammetakkurtt--crypto-twitter-tracker.apify.actor
CHANNELS=tweets
USERS=elonmusk,vitalikbuterin,cz_binance
KEYWORDS=bitcoin,ethereum,crypto
DASHBOARD_ENABLED=true
DASHBOARD_PORT=3000
CLI_ENABLED=falseReceive alerts on Telegram without CLI or dashboard.
.env:
APIFY_TOKEN=your_token_here
APIFY_ACTOR_URL=https://muhammetakkurtt--crypto-twitter-tracker.apify.actor
CHANNELS=all
CLI_ENABLED=false
DASHBOARD_ENABLED=false
TELEGRAM_ENABLED=true
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrsTUVwxyz
TELEGRAM_CHAT_ID=123456789Use all output channels simultaneously.
.env:
APIFY_TOKEN=your_token_here
APIFY_ACTOR_URL=https://muhammetakkurtt--crypto-twitter-tracker.apify.actor
CHANNELS=all
USERS=elonmusk,vitalikbuterin
KEYWORDS=bitcoin,ethereum
# CLI
CLI_ENABLED=true
CLI_STATS_INTERVAL=60000
# Dashboard
DASHBOARD_ENABLED=true
DASHBOARD_PORT=3000
# Telegram
TELEGRAM_ENABLED=true
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrsTUVwxyz
TELEGRAM_CHAT_ID=123456789
# Discord
DISCORD_ENABLED=true
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/123456789/abcdefg
# Webhook
WEBHOOK_ENABLED=true
WEBHOOK_URL=https://your-webhook-url.com/endpointConfiguration optimized for high-volume streams.
.env:
APIFY_TOKEN=your_token_here
APIFY_ACTOR_URL=https://muhammetakkurtt--crypto-twitter-tracker.apify.actor
CHANNELS=all
# Shorter dedup TTL for high volume
DEDUP_TTL=30
# Faster reconnection
RECONNECT_INITIAL_DELAY=500
RECONNECT_MAX_DELAY=10000
# More frequent stats
CLI_STATS_INTERVAL=30000
# Higher rate limit
ALERT_RATE_LIMIT=20Use different configurations for development and production.
Development (.env.development):
APIFY_TOKEN=dev_token_here
APIFY_ACTOR_URL=https://muhammetakkurtt--crypto-twitter-tracker.apify.actor
CHANNELS=tweets
USERS=testuser1,testuser2
DASHBOARD_ENABLED=true
DASHBOARD_PORT=3000
CLI_ENABLED=true
TELEGRAM_ENABLED=falseProduction (.env.production):
APIFY_TOKEN=prod_token_here
APIFY_ACTOR_URL=https://muhammetakkurtt--crypto-twitter-tracker.apify.actor
CHANNELS=all
DASHBOARD_ENABLED=true
DASHBOARD_PORT=8080
CLI_ENABLED=false
TELEGRAM_ENABLED=true
TELEGRAM_BOT_TOKEN=prod_bot_token
TELEGRAM_CHAT_ID=prod_chat_id
DISCORD_ENABLED=true
DISCORD_WEBHOOK_URL=prod_webhook_urlUse JSON for non-sensitive settings and environment variables for secrets.
config/config.json:
{
"apify": {
"channels": ["tweets"]
},
"filters": {
"users": ["elonmusk", "vitalikbuterin"],
"keywords": ["bitcoin", "ethereum"]
},
"outputs": {
"cli": {
"enabled": true,
"statsInterval": 60000
},
"dashboard": {
"enabled": true,
"port": 3000
},
"alerts": {
"telegram": {
"enabled": true
}
}
}
}.env:
# Secrets only
APIFY_TOKEN=your_token_here
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrsTUVwxyz
TELEGRAM_CHAT_ID=123456789Fine-tune reconnection behavior for your network conditions.
Aggressive Reconnection (fast recovery, more network traffic):
RECONNECT_INITIAL_DELAY=500
RECONNECT_MAX_DELAY=5000
RECONNECT_BACKOFF_MULTIPLIER=1.5
RECONNECT_MAX_ATTEMPTS=0Conservative Reconnection (slower recovery, less network traffic):
RECONNECT_INITIAL_DELAY=5000
RECONNECT_MAX_DELAY=60000
RECONNECT_BACKOFF_MULTIPLIER=2.5
RECONNECT_MAX_ATTEMPTS=10Adjust deduplication based on your use case.
High-Volume Streams (shorter TTL, less memory):
DEDUP_TTL=30Low-Volume Streams (longer TTL, more duplicate protection):
DEDUP_TTL=300No Deduplication (not recommended):
DEDUP_TTL=0Adjust rate limits based on your alert channel limits.
Telegram (official limit: 30 messages/second per chat):
ALERT_RATE_LIMIT=20 # Conservative limitDiscord (official limit: 5 requests/second per webhook):
ALERT_RATE_LIMIT=10 # Conservative limitCustom Webhook (depends on your service):
ALERT_RATE_LIMIT=50 # Adjust based on your service limitsThe application supports runtime modification of subscription parameters through the dashboard interface. This section explains how runtime changes interact with configuration files.
Configuration File (.env or config.json):
- Defines the initial subscription state at startup
- Persists across restarts
- Source field: "config"
Runtime Changes (via dashboard):
- Modify subscription without restarting
- Temporary - do not persist across restarts
- Source field: "runtime"
When you modify the subscription via the dashboard:
- Immediate Effect: Changes are applied immediately to the active connection
- Broadcast: All connected dashboards receive the update
- Temporary: Changes are stored in memory only
- Restart Behavior: After restart, the application reverts to configuration file settings
Example Flow:
Startup:
Load from .env: CHANNELS=all, USERS=elonmusk
State: { channels: ["all"], users: ["elonmusk"], source: "config" }
↓
Runtime Change (via dashboard):
User changes to: channels=["tweets"], users=["elonmusk", "vitalikbuterin"]
State: { channels: ["tweets"], users: ["elonmusk", "vitalikbuterin"], source: "runtime" }
↓
Restart:
Load from .env: CHANNELS=all, USERS=elonmusk
State: { channels: ["all"], users: ["elonmusk"], source: "config" }
(Runtime changes are lost)
The source field in the subscription state indicates the origin of the current configuration:
"config":
- Subscription loaded from configuration file at startup
- No runtime modifications have been made
- Matches
.envorconfig.jsonsettings
"runtime":
- Subscription modified via dashboard
- May differ from configuration file
- Will revert to "config" after restart
Checking Source:
socket.emit('getRuntimeSubscription', (response) => {
if (response.data.source === 'config') {
console.log('Using configuration file settings');
} else {
console.log('Modified at runtime - will revert after restart');
}
});Runtime changes are temporary by design. To make changes permanent, you must update your configuration file.
Step 1: Note Current Runtime State
Via dashboard or API:
socket.emit('getRuntimeSubscription', (response) => {
console.log('Current channels:', response.data.channels);
console.log('Current users:', response.data.users);
});Step 2: Update Configuration File
Edit .env:
# Update to match runtime state
CHANNELS=tweets,following
USERS=elonmusk,vitalikbuterin,cz_binanceOr edit config/config.json:
{
"apify": {
"channels": ["tweets", "following"]
},
"filters": {
"users": ["elonmusk", "vitalikbuterin", "cz_binance"]
}
}Step 3: Restart Application
npm startAfter restart:
- Subscription loads from configuration file
- Source field changes to "config"
- Changes are now permanent
The configuration priority system applies only at startup:
Startup: Environment Variables > config.json > Default Values
Runtime: Dashboard changes override everything (temporarily)
Restart: Back to startup priority
Example:
# .env
CHANNELS=all
USERS=elonmusk// config.json
{
"apify": {
"channels": ["tweets"]
}
}At Startup:
- Environment variable wins:
channels: ["all"] - Source: "config"
After Runtime Change:
- Dashboard sets:
channels: ["following"] - Source: "runtime"
- Configuration files are ignored (temporarily)
After Restart:
- Environment variable wins again:
channels: ["all"] - Source: "config"
- Runtime changes are lost
1. Use Runtime Changes for Experimentation
Runtime changes are perfect for testing different configurations:
- Try different channel combinations
- Test user filters
- Experiment with idle mode
- No need to restart or edit files
2. Update Configuration Files for Production
Once you've found a configuration that works:
- Update
.envorconfig.json - Restart to verify configuration loads correctly
- Document the change in version control
3. Monitor Source Field
Check the source field to know if runtime changes are active:
socket.on('runtimeSubscriptionUpdated', (state) => {
if (state.source === 'runtime') {
console.warn('Runtime changes active - will revert after restart');
}
});4. Document Runtime Changes
If you make runtime changes in production:
- Document what was changed and why
- Update configuration files before next restart
- Notify team members of temporary changes
Problem: Runtime changes not persisting after restart
Solution: This is expected behavior. Runtime changes are temporary. Update configuration files to make changes permanent.
Problem: Configuration file changes not taking effect
Solution: Runtime changes override configuration. Restart the application to load configuration file settings.
Problem: Source field shows "runtime" but I didn't make changes
Solution: Another client (dashboard instance) made runtime changes. Check with team members or restart to revert to configuration.
Problem: Can't modify subscription from dashboard
Solution: Only control clients (localhost) can modify subscriptions. Remote clients are read-only for security.
You want to temporarily reduce costs without editing configuration:
- Open dashboard (localhost)
- Change users to a smaller set
- Apply changes
- Monitor for desired period
- Restart to revert to full configuration
You want to test new user filters before committing:
- Make runtime changes via dashboard
- Monitor events for a few hours
- If satisfied, update
.envfile - Restart to make permanent
You need to pause monitoring immediately:
- Open dashboard
- Uncheck all channels (idle mode)
- Apply changes
- Monitoring pauses immediately
- Restart later to resume with configuration
Multiple team members have dashboards open:
- Team member A makes runtime change
- All dashboards receive broadcast
- All dashboards show updated state
- Source field shows "runtime" for everyone
- After restart, all revert to configuration
-
Never commit secrets to version control
- Use
.envfor secrets (add to.gitignore) - Use
config.jsonfor non-sensitive settings
- Use
-
Use environment-specific configurations
.env.developmentfor development.env.productionfor production- Load the appropriate file based on
NODE_ENV
-
Rotate tokens regularly
- Generate new Apify tokens periodically
- Update bot tokens if compromised
-
Restrict access
- Use firewall rules to limit access to dashboard and health endpoints
- Consider adding authentication for production deployments
-
Optimize filters
- Use specific user filters to reduce processing
- Use targeted keywords to reduce noise
-
Tune deduplication
- Lower TTL for high-volume streams
- Higher TTL for low-volume streams
-
Disable unused outputs
- Set
CLI_ENABLED=falseif not using CLI - Disable alert channels you're not using
- Set
-
Monitor resource usage
- Check
/statusendpoint regularly - Monitor memory usage with long-running instances
- Check
-
Use infinite reconnection attempts
- Set
RECONNECT_MAX_ATTEMPTS=0for production - Ensures the application recovers from temporary outages
- Set
-
Configure appropriate backoff
- Use exponential backoff to avoid overwhelming the server
- Set reasonable max delay (30-60 seconds)
-
Enable health monitoring
- Expose
/statusendpoint for monitoring systems - Set up alerts for connection failures
- Expose
-
Use multiple output channels
- Enable both dashboard and alerts for redundancy
- If one channel fails, others continue working
-
Use config.json for team settings
- Commit non-sensitive configuration
- Share common filters and settings
-
Use .env for personal settings
- Keep personal tokens in
.env(gitignored) - Override team settings as needed
- Keep personal tokens in
-
Test with different channels
- Start with
CHANNELS=tweetsfor lower volume - Test filters with specific users
- Start with
-
Monitor logs during development
- Enable CLI output for debugging
- Check for parsing errors and connection issues
Problem: Changes to .env or config.json not taking effect
Solutions:
- Restart the application after configuration changes
- Verify file paths are correct (
config/config.json, notconfig.json) - Check for syntax errors in JSON files
- Ensure
.envfile is in the project root
Problem: Environment variables not being read
Solutions:
- Verify
.envfile exists in project root - Check for typos in variable names (case-sensitive)
- Ensure no spaces around
=(useKEY=value, notKEY = value) - Restart the application after changes
Problem: Wrong configuration value being used
Solutions:
- Remember priority: Environment Variables > config.json > Defaults
- Check if the same setting exists in multiple places
- Use environment variables to override config.json
- Remove conflicting settings from config.json
Problem: Application fails to start due to invalid configuration
Solutions:
- Check logs for specific error messages
- Verify data types (numbers vs strings)
- Ensure boolean values are
trueorfalse(notyes/no) - Validate URLs are complete and properly formatted
Problem: Application connects successfully but no events are received
This is the most common issue when using user filtering. Here's how to diagnose and fix it:
Symptom: Startup shows validation warnings about usernames not in the returned list
Example Warning:
⚠️ WARNING: User filter validation notice!
The following usernames are NOT in the returned monitored users list:
someuser, anotheruser
Note: The actor may monitor additional users beyond this list.
If these users are monitored by the actor, you WILL receive their events.
What This Means:
- These usernames are not in the
/active-usersendpoint response - The actor may still monitor them (the endpoint returns a subset)
- If the actor doesn't monitor them, you won't receive events
Solution:
-
Check the monitored users list for reference:
curl -H "Authorization: Bearer YOUR_TOKEN" \ https://muhammetakkurtt--crypto-twitter-tracker.apify.actor/active-users -
If your usernames are not in the list, you have two options:
- Keep them (actor may still monitor them)
- Replace with usernames from the list (guaranteed to work)
-
Restart the application
Symptom: All your configured usernames show validation warnings
Solution:
-
Remove the
USERSfilter temporarily to verify the connection works:USERS=
-
Check which users are in the returned list:
curl -H "Authorization: Bearer YOUR_TOKEN" \ https://muhammetakkurtt--crypto-twitter-tracker.apify.actor/active-users -
Configure usernames from the list (or keep your usernames if you believe the actor monitors them)
Symptom: You configured usernames but they have typos or wrong format
Common Mistakes:
- Including @ symbol:
@elonmusk(wrong) vselonmusk(correct) - Wrong capitalization: Usernames are case-insensitive
- Spaces in the list:
elon musk, vitalik(wrong) vselonmusk,vitalikbuterin(correct) - Display names instead of usernames:
Elon Musk(wrong) vselonmusk(correct)
Solution:
- Remove @ symbols
- Remove spaces between usernames
- Use actual Twitter usernames (not display names)
- Verify format is correct
Symptom: Valid usernames but still no events
Solution:
- The accounts you're monitoring may not be posting during your test period
- Try adding a high-volume account like
elonmuskto verify the connection works - Check Twitter directly to see if those accounts are posting
- Wait a few minutes - some accounts post infrequently
Symptom: Using both USERS and KEYWORDS filters
Example:
USERS=elonmusk
KEYWORDS=veryspecifickeywordSolution:
- Actor-side filtering (USERS) reduces events to only those users
- Client-side filtering (KEYWORDS) further reduces events
- If keywords are too specific, you may receive no events
- Try removing
KEYWORDStemporarily to verify events are being received
Follow these steps to diagnose empty event stream issues:
-
Check connection status:
curl http://localhost:3001/status
Verify
connection.statusis"connected" -
Check validation warnings: Look at application startup logs for advisory warnings about usernames
-
Test without filters:
USERS= KEYWORDS=
If events appear, your filters are too restrictive
-
Test with a user from the returned list:
USERS=elonmusk
If events appear, your original usernames may not be monitored
-
Check monitored users list for reference:
curl -H "Authorization: Bearer YOUR_TOKEN" \ https://muhammetakkurtt--crypto-twitter-tracker.apify.actor/active-usersCompare your usernames with this list
-
Check actor health:
curl -H "Authorization: Bearer YOUR_TOKEN" \ https://muhammetakkurtt--crypto-twitter-tracker.apify.actor/healthVerify the actor is running and healthy
- Check if usernames are in the returned monitored users list (for reference)
- No @ symbols in usernames
- No spaces between comma-separated usernames
- Using usernames, not display names
- Understand that actor may monitor users not in the returned list
- Application shows validation success on startup
- Connection status is "connected"
- Filters are not overly restrictive
- Monitored accounts are actually posting
For a complete list of all configuration options with examples, see:
.env.example- All environment variablesconfig/config.example.json- JSON configuration example
If you need help with configuration:
- Check this guide and the examples
- Review the README.md troubleshooting section
- Check the API Documentation for endpoint details
- Open an issue on GitHub with your configuration (sanitize tokens!)