What can we help you with?
Tavily API Quick Reference – Factchecker Plugin
Tavily API Quick Reference – Factchecker Plugin
For Developers: Quick reference for implementing Tavily integration
Primary Endpoint: Search
Request
POST https://api.tavily.com/search
{
"api_key": "tvly-xxxxxxxxxxxxx",
"query": "electric vehicle sales 2023 statistics",
"search_depth": "advanced",
"include_answer": true,
"include_raw_content": false,
"max_results": 5,
"include_domains": ["reuters.com", "apnews.com", ".gov", ".edu"],
"exclude_domains": ["unreliablesource.com"],
"include_images": false
}
Response
{
"query": "electric vehicle sales 2023 statistics",
"answer": "Electric vehicle sales increased by approximately 40% in 2023...",
"results": [
{
"title": "Global EV Outlook 2024",
"url": "https://iea.org/reports/global-ev-outlook-2024",
"content": "Electric vehicle sales reached record levels in 2023, with a 40% increase...",
"score": 0.95,
"published_date": "2024-03-15"
},
{
"title": "EV Sales Hit Record in 2023",
"url": "https://bloomberg.com/news/ev-sales-2023",
"content": "Bloomberg analysis shows electric vehicle sales grew 40% year-over-year...",
"score": 0.92,
"published_date": "2024-01-10"
}
],
"response_time": 1.23,
"images": []
}
Parameters Reference
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
api_key |
string | Yes | – | Your Tavily API key |
query |
string | Yes | – | Search query (max 400 chars) |
search_depth |
string | No | “basic” | “basic” or “advanced” |
include_answer |
boolean | No | false | Include AI-generated summary |
include_raw_content |
boolean | No | false | Include full page content |
max_results |
integer | No | 5 | Number of results (1-10) |
include_domains |
array | No | [] | Whitelist domains |
exclude_domains |
array | No | [] | Blacklist domains |
include_images |
boolean | No | false | Include image results |
Search Depth Comparison
| Feature | Basic | Advanced |
|---|---|---|
| Sources searched | Fewer | More comprehensive |
| Response time | ~1-2 seconds | ~2-4 seconds |
| Result quality | Good | Excellent |
| Cost | 1 credit | 2 credits |
| Best for | Quick checks, common facts | Critical claims, research |
WordPress Implementation Example
1. Store API Key Securely
// Save API key (encrypted)
update_option('factchecker_tavily_api_key',
openssl_encrypt($api_key, 'AES-256-CBC', SECURE_KEY, 0, SECURE_IV)
);
// Retrieve API key
$encrypted_key = get_option('factchecker_tavily_api_key');
$api_key = openssl_decrypt($encrypted_key, 'AES-256-CBC', SECURE_KEY, 0, SECURE_IV);
2. Make API Request
function factchecker_tavily_search($query, $max_results = 5) {
$api_key = factchecker_get_tavily_api_key();
if (empty($api_key)) {
return new WP_Error('no_api_key', 'Tavily API key not configured');
}
// Check cache first
$cache_key = 'tavily_' . md5($query . $max_results);
$cached = get_transient($cache_key);
if ($cached !== false) {
return $cached;
}
$body = json_encode([
'api_key' => $api_key,
'query' => $query,
'search_depth' => get_option('factchecker_tavily_depth', 'advanced'),
'include_answer' => true,
'max_results' => $max_results,
'include_domains' => factchecker_get_trusted_domains(),
'exclude_domains' => factchecker_get_blocked_domains(),
]);
$response = wp_remote_post('https://api.tavily.com/search', [
'timeout' => 30,
'headers' => [
'Content-Type' => 'application/json',
],
'body' => $body,
]);
if (is_wp_error($response)) {
return $response;
}
$status_code = wp_remote_retrieve_response_code($response);
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
// Handle errors
if ($status_code !== 200) {
return factchecker_handle_tavily_error($status_code, $data);
}
// Cache successful response for 24 hours
set_transient($cache_key, $data, DAY_IN_SECONDS);
// Track usage
factchecker_increment_tavily_usage();
return $data;
}
3. Process Results
function factchecker_process_tavily_results($results, $claim) {
if (empty($results['results'])) {
return [
'status' => 'unverified',
'confidence' => 'low',
'message' => 'No sources found to verify this claim.',
'sources' => []
];
}
$sources = [];
$high_credibility_count = 0;
foreach ($results['results'] as $result) {
$credibility = factchecker_assess_source_credibility($result['url']);
if ($credibility === 'tier1' || $credibility === 'tier2') {
$high_credibility_count++;
}
$sources[] = [
'title' => $result['title'],
'url' => $result['url'],
'excerpt' => $result['content'],
'published_date' => $result['published_date'] ?? null,
'credibility' => $credibility,
'relevance_score' => $result['score'],
];
}
// Determine verification status
if ($high_credibility_count >= 3) {
$status = 'verified';
$confidence = 'high';
$message = 'Multiple authoritative sources confirm this claim.';
} elseif ($high_credibility_count >= 1) {
$status = 'partially_verified';
$confidence = 'medium';
$message = 'Limited source support. Consider additional verification.';
} else {
$status = 'unverified';
$confidence = 'low';
$message = 'No highly credible sources found.';
}
return [
'status' => $status,
'confidence' => $confidence,
'message' => $message,
'sources' => $sources,
'ai_summary' => $results['answer'] ?? null,
];
}
4. Source Credibility Assessment
function factchecker_assess_source_credibility($url) {
$domain = parse_url($url, PHP_URL_HOST);
// Tier 1: Highest credibility
$tier1_patterns = [
'/\.gov$/',
'/\.mil$/',
'/\.edu$/',
'/^(www\.)?(reuters|apnews|bbc|npr)\.com$/',
'/^(www\.)?(who|un|worldbank)\./',
];
foreach ($tier1_patterns as $pattern) {
if (preg_match($pattern, $domain)) {
return 'tier1';
}
}
// Tier 2: High credibility
$tier2_domains = [
'nytimes.com', 'washingtonpost.com', 'theguardian.com',
'bloomberg.com', 'wsj.com', 'economist.com',
'nature.com', 'science.org', 'pnas.org',
'factcheck.org', 'snopes.com', 'politifact.com',
];
foreach ($tier2_domains as $trusted) {
if (strpos($domain, $trusted) !== false) {
return 'tier2';
}
}
// Tier 3: Moderate credibility
return 'tier3';
}
Error Handling
HTTP Status Codes
function factchecker_handle_tavily_error($status_code, $data) {
switch ($status_code) {
case 401:
return new WP_Error(
'tavily_auth_failed',
'Invalid Tavily API key. Please check your settings.',
['status' => 401]
);
case 429:
return new WP_Error(
'tavily_rate_limit',
'Tavily API rate limit exceeded. Using cached results only.',
['status' => 429]
);
case 500:
case 503:
return new WP_Error(
'tavily_server_error',
'Tavily service temporarily unavailable. Continuing without real-time verification.',
['status' => $status_code]
);
default:
return new WP_Error(
'tavily_unknown_error',
'Unexpected error from Tavily API.',
['status' => $status_code, 'data' => $data]
);
}
}
Usage Tracking
Track API Calls
function factchecker_increment_tavily_usage() {
$current_month = date('Y-m');
$usage_key = 'factchecker_tavily_usage_' . $current_month;
$usage = get_option($usage_key, 0);
update_option($usage_key, $usage + 1);
// Check if approaching limit
$quota = get_option('factchecker_tavily_quota', 1000);
if ($usage >= $quota * 0.8) {
factchecker_send_quota_warning($usage, $quota);
}
}
function factchecker_get_tavily_usage() {
$current_month = date('Y-m');
$usage_key = 'factchecker_tavily_usage_' . $current_month;
return get_option($usage_key, 0);
}
Cache Management
function factchecker_get_cache_stats() {
global $wpdb;
$cache_count = $wpdb->get_var(
"SELECT COUNT(*) FROM {$wpdb->options}
WHERE option_name LIKE '_transient_tavily_%'"
);
return [
'cached_queries' => $cache_count,
'cache_size' => factchecker_get_cache_size(),
];
}
function factchecker_clear_tavily_cache() {
global $wpdb;
$wpdb->query(
"DELETE FROM {$wpdb->options}
WHERE option_name LIKE '_transient_tavily_%'
OR option_name LIKE '_transient_timeout_tavily_%'"
);
return true;
}
Query Optimization
Generate Effective Queries
function factchecker_generate_tavily_query($claim) {
// Remove common words
$stopwords = ['the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for'];
$words = explode(' ', strtolower($claim));
$words = array_diff($words, $stopwords);
// Extract key terms
$query = implode(' ', $words);
// Add context for better results
if (preg_match('/\d{4}/', $claim, $year)) {
// Year found, ensure it's in query
if (strpos($query, $year[0]) === false) {
$query .= ' ' . $year[0];
}
}
// Limit length
if (strlen($query) > 200) {
$query = substr($query, 0, 200);
}
return trim($query);
}
Batch Similar Queries
function factchecker_batch_tavily_queries($claims) {
$queries = [];
foreach ($claims as $claim) {
$query = factchecker_generate_tavily_query($claim);
// Check for similar existing queries
$similar_found = false;
foreach ($queries as &$existing) {
if (similar_text($query, $existing['query']) > 0.8) {
$existing['claims'][] = $claim;
$similar_found = true;
break;
}
}
if (!$similar_found) {
$queries[] = [
'query' => $query,
'claims' => [$claim],
];
}
}
return $queries;
}
Admin Settings UI
Settings Page Structure
function factchecker_render_tavily_settings() {
?>
<div class="wrap">
<h1>Tavily Integration Settings</h1>
<form method="post" action="options.php">
<?php settings_fields('factchecker_tavily'); ?>
<table class="form-table">
<tr>
<th scope="row">Enable Tavily</th>
<td>
<label>
<input type="checkbox"
name="factchecker_tavily_enabled"
value="1"
<?php checked(get_option('factchecker_tavily_enabled'), 1); ?>>
Enable real-time source verification
</label>
</td>
</tr>
<tr>
<th scope="row">API Key</th>
<td>
<input type="password"
name="factchecker_tavily_api_key"
value="<?php echo esc_attr(factchecker_get_tavily_api_key_masked()); ?>"
class="regular-text">
<p class="description">
<a href="https://tavily.com/signup" target="_blank">Get your API key</a>
</p>
<button type="button"
class="button"
id="test-tavily-connection">
Test Connection
</button>
<span id="tavily-test-result"></span>
</td>
</tr>
<tr>
<th scope="row">Search Depth</th>
<td>
<label>
<input type="radio"
name="factchecker_tavily_depth"
value="basic"
<?php checked(get_option('factchecker_tavily_depth', 'advanced'), 'basic'); ?>>
Basic (faster, fewer sources)
</label><br>
<label>
<input type="radio"
name="factchecker_tavily_depth"
value="advanced"
<?php checked(get_option('factchecker_tavily_depth', 'advanced'), 'advanced'); ?>>
Advanced (thorough, more sources)
</label>
</td>
</tr>
<tr>
<th scope="row">Usage This Month</th>
<td>
<?php
$usage = factchecker_get_tavily_usage();
$quota = get_option('factchecker_tavily_quota', 1000);
$percentage = ($usage / $quota) * 100;
?>
<div class="tavily-usage-bar">
<div class="tavily-usage-progress"
style="width: <?php echo $percentage; ?>%"></div>
</div>
<p><?php echo $usage; ?> / <?php echo $quota; ?> (<?php echo round($percentage, 1); ?>%)</p>
<button type="button"
class="button"
id="clear-tavily-cache">
Clear Cache
</button>
</td>
</tr>
</table>
<?php submit_button(); ?>
</form>
</div>
<?php
}
Testing
Test Connection
function factchecker_test_tavily_connection() {
$result = factchecker_tavily_search('test query', 1);
if (is_wp_error($result)) {
return [
'success' => false,
'message' => $result->get_error_message(),
];
}
return [
'success' => true,
'message' => 'Connection successful! Tavily is working correctly.',
'response_time' => $result['response_time'] ?? null,
];
}
AJAX Handler
add_action('wp_ajax_factchecker_test_tavily', 'factchecker_ajax_test_tavily');
function factchecker_ajax_test_tavily() {
check_ajax_referer('factchecker_settings', 'nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error(['message' => 'Unauthorized']);
}
$result = factchecker_test_tavily_connection();
if ($result['success']) {
wp_send_json_success($result);
} else {
wp_send_json_error($result);
}
}
Rate Limiting
Client-Side Rate Limiting
function factchecker_check_rate_limit() {
$usage = factchecker_get_tavily_usage();
$quota = get_option('factchecker_tavily_quota', 1000);
if ($usage >= $quota) {
return new WP_Error(
'quota_exceeded',
'Monthly Tavily quota exceeded. Using cached results only.'
);
}
return true;
}
Best Practices
1. Always Check Cache First
// ✅ Good
$cached = get_transient($cache_key);
if ($cached !== false) return $cached;
$result = factchecker_tavily_search($query);
// ❌ Bad
$result = factchecker_tavily_search($query); // Wastes API calls
2. Handle Errors Gracefully
// ✅ Good
$result = factchecker_tavily_search($query);
if (is_wp_error($result)) {
// Continue with local analysis
return factchecker_local_verification($claim);
}
// ❌ Bad
$result = factchecker_tavily_search($query);
// No error handling - analysis fails completely
3. Limit Queries Per Analysis
// ✅ Good
$max_queries = 10;
$queries_made = 0;
foreach ($claims as $claim) {
if ($queries_made >= $max_queries) break;
// Process claim
$queries_made++;
}
// ❌ Bad
foreach ($claims as $claim) {
// No limit - could make 100+ queries
}
4. Use Appropriate Search Depth
// ✅ Good
$depth = $is_critical_claim ? 'advanced' : 'basic';
// ❌ Bad
$depth = 'advanced'; // Always uses 2x credits
Troubleshooting
Common Issues
Issue: “Invalid API key”
- Check: API key is correct and not expired
- Check: API key is properly decrypted
- Solution: Re-enter API key in settings
Issue: “Rate limit exceeded”
- Check: Current usage vs. quota
- Solution: Clear cache, upgrade plan, or wait for reset
Issue: “Slow response times”
- Check: Using ‘advanced’ depth unnecessarily
- Check: Too many results requested
- Solution: Use ‘basic’ depth, reduce max_results
Issue: “No results returned”
- Check: Query is well-formed
- Check: Not too specific or too vague
- Solution: Improve query generation logic
Resources
- Tavily Documentation: https://docs.tavily.com
- API Reference: https://docs.tavily.com/api-reference
- Pricing: https://tavily.com/pricing
- Support: support@tavily.com
Last Updated: January 9, 2026
