Skip to main content

data_for_seo/api/domain_analytics/
technologies.rs

1use crate::api::domain_analytics::DomainAnalyticsApi;
2use crate::entity::{
3    DomainAnalyticsApiAggregationTechnologies, DomainAnalyticsApiAvailableTechnologies,
4    DomainAnalyticsApiDomainTechnologyItem, DomainAnalyticsApiDomainsByHtmlTerms,
5    DomainAnalyticsApiDomainsByTechnology, DomainAnalyticsApiTechnologiesSummary,
6    DomainAnalyticsApiTechnologyStats,
7};
8use crate::{DataForSeoApiResponse, DataForSeoClient};
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11
12impl DomainAnalyticsApi<'_> {
13    /// Returns the Technologies sub-API builder.
14    pub fn technologies(&self) -> DomainAnalyticsApiTechnologies<'_> {
15        DomainAnalyticsApiTechnologies {
16            client: self.client,
17        }
18    }
19}
20
21/// Builder for the [Domain Analytics Technologies](https://docs.dataforseo.com/v3/domain_analytics/technologies/overview/) endpoints.
22pub struct DomainAnalyticsApiTechnologies<'a> {
23    client: &'a DataForSeoClient,
24}
25
26impl DomainAnalyticsApiTechnologies<'_> {
27    /// Returns the full catalogue of detectable technologies grouped by group and category.
28    /// See <https://docs.dataforseo.com/v3/domain_analytics/technologies/technologies/>.
29    pub async fn available_technologies(
30        &self,
31    ) -> DataForSeoApiResponse<DomainAnalyticsApiAvailableTechnologies> {
32        self.client
33            .http_get("/v3/domain_analytics/technologies/technologies")
34            .await
35    }
36
37    /// Returns domain counts aggregated by technology group, category, and technology.
38    /// See <https://docs.dataforseo.com/v3/domain_analytics/technologies/aggregation_technologies/live/>.
39    pub async fn aggregation_technologies(
40        &self,
41        data: Vec<DomainAnalyticsApiAggregationTechnologiesPost>,
42    ) -> DataForSeoApiResponse<DomainAnalyticsApiAggregationTechnologies> {
43        self.client
44            .http_post(
45                "/v3/domain_analytics/technologies/aggregation_technologies/live",
46                &data,
47            )
48            .await
49    }
50
51    /// Returns a distribution of matching domains across countries, languages, and keywords.
52    /// See <https://docs.dataforseo.com/v3/domain_analytics/technologies/technologies_summary/live/>.
53    pub async fn technologies_summary(
54        &self,
55        data: Vec<DomainAnalyticsApiTechnologiesSummaryPost>,
56    ) -> DataForSeoApiResponse<DomainAnalyticsApiTechnologiesSummary> {
57        self.client
58            .http_post(
59                "/v3/domain_analytics/technologies/technologies_summary/live",
60                &data,
61            )
62            .await
63    }
64
65    /// Returns the historical adoption of a single technology over time.
66    /// See <https://docs.dataforseo.com/v3/domain_analytics/technologies/technology_stats/live/>.
67    pub async fn technology_stats(
68        &self,
69        data: Vec<DomainAnalyticsApiTechnologyStatsPost>,
70    ) -> DataForSeoApiResponse<DomainAnalyticsApiTechnologyStats> {
71        self.client
72            .http_post(
73                "/v3/domain_analytics/technologies/technology_stats/live",
74                &data,
75            )
76            .await
77    }
78
79    /// Returns the list of domains using the requested technologies.
80    /// See <https://docs.dataforseo.com/v3/domain_analytics/technologies/domains_by_technology/live/>.
81    pub async fn domains_by_technology(
82        &self,
83        data: Vec<DomainAnalyticsApiDomainsByTechnologyPost>,
84    ) -> DataForSeoApiResponse<DomainAnalyticsApiDomainsByTechnology> {
85        self.client
86            .http_post(
87                "/v3/domain_analytics/technologies/domains_by_technology/live",
88                &data,
89            )
90            .await
91    }
92
93    /// Returns the list of domains whose HTML contains the requested terms.
94    /// See <https://docs.dataforseo.com/v3/domain_analytics/technologies/domains_by_html_terms/live/>.
95    pub async fn domains_by_html_terms(
96        &self,
97        data: Vec<DomainAnalyticsApiDomainsByHtmlTermsPost>,
98    ) -> DataForSeoApiResponse<DomainAnalyticsApiDomainsByHtmlTerms> {
99        self.client
100            .http_post(
101                "/v3/domain_analytics/technologies/domains_by_html_terms/live",
102                &data,
103            )
104            .await
105    }
106
107    /// Returns the technologies detected for a single target domain.
108    /// See <https://docs.dataforseo.com/v3/domain_analytics/technologies/domain_technologies/live/>.
109    pub async fn domain_technologies(
110        &self,
111        data: Vec<DomainAnalyticsApiDomainTechnologiesPost>,
112    ) -> DataForSeoApiResponse<DomainAnalyticsApiDomainTechnologyItem> {
113        self.client
114            .http_post(
115                "/v3/domain_analytics/technologies/domain_technologies/live",
116                &data,
117            )
118            .await
119    }
120}
121
122/// A target technology path (`$group_id.$category_id`) with an optional display name.
123#[derive(Debug, Default, Serialize, Deserialize, Clone)]
124pub struct DomainAnalyticsApiTechnologyPath {
125    /// Technology path in the form `$group_id.$category_id`.
126    pub path: String,
127    /// Optional display name of the technology.
128    #[serde(skip_serializing_if = "Option::is_none")]
129    pub name: Option<String>,
130}
131
132impl DomainAnalyticsApiTechnologyPath {
133    /// Creates a technology path targeting `$group_id.$category_id`.
134    pub fn new(path: String) -> DomainAnalyticsApiTechnologyPath {
135        DomainAnalyticsApiTechnologyPath {
136            path,
137            ..Default::default()
138        }
139    }
140}
141
142/// Request body for the `aggregation_technologies` endpoint.
143///
144/// At least one of `group`, `category`, `technology`, or `keyword` must be set.
145#[derive(Debug, Default, Serialize, Deserialize, Clone)]
146pub struct DomainAnalyticsApiAggregationTechnologiesPost {
147    /// Technology group ID to aggregate on.
148    #[serde(skip_serializing_if = "Option::is_none")]
149    pub group: Option<String>,
150    /// Technology category ID to aggregate on.
151    #[serde(skip_serializing_if = "Option::is_none")]
152    pub category: Option<String>,
153    /// Technology name to aggregate on.
154    #[serde(skip_serializing_if = "Option::is_none")]
155    pub technology: Option<String>,
156    /// Domain meta keyword to aggregate on.
157    #[serde(skip_serializing_if = "Option::is_none")]
158    pub keyword: Option<String>,
159    /// Match mode: `as_is` (exact, default) or `entry` (partial).
160    #[serde(skip_serializing_if = "Option::is_none")]
161    pub mode: Option<String>,
162    /// Result filters, each a `[field, operator, value]` array (max 8).
163    #[serde(skip_serializing_if = "Option::is_none")]
164    pub filters: Option<Vec<Value>>,
165    /// Sorting rules such as `["technologies_count,desc"]`.
166    #[serde(skip_serializing_if = "Option::is_none")]
167    pub order_by: Option<Vec<String>>,
168    /// Maximum number of groups returned (default 5, max 10000).
169    #[serde(skip_serializing_if = "Option::is_none")]
170    pub internal_groups_list_limit: Option<i32>,
171    /// Maximum number of categories per group (default 5, max 10000).
172    #[serde(skip_serializing_if = "Option::is_none")]
173    pub internal_categories_list_limit: Option<i32>,
174    /// Maximum number of technologies per category (default 10, max 10000).
175    #[serde(skip_serializing_if = "Option::is_none")]
176    pub internal_technologies_list_limit: Option<i32>,
177    /// Maximum number of items with identical group/category/technology (default 10, max 10000).
178    #[serde(skip_serializing_if = "Option::is_none")]
179    pub internal_list_limit: Option<i32>,
180    /// Maximum number of returned technologies (default 100, max 10000).
181    #[serde(skip_serializing_if = "Option::is_none")]
182    pub limit: Option<i32>,
183    /// Offset in the results array (default 0, max 9999).
184    #[serde(skip_serializing_if = "Option::is_none")]
185    pub offset: Option<i32>,
186    /// User-defined task identifier (max 255 characters).
187    #[serde(skip_serializing_if = "Option::is_none")]
188    pub tag: Option<String>,
189}
190
191impl DomainAnalyticsApiAggregationTechnologiesPost {
192    /// Creates an empty request. Set one of `group`/`category`/`technology`/`keyword`.
193    pub fn new() -> DomainAnalyticsApiAggregationTechnologiesPost {
194        DomainAnalyticsApiAggregationTechnologiesPost::default()
195    }
196}
197
198/// Request body for the `technologies_summary` endpoint.
199///
200/// At least one of `technology_paths`, `groups`, `categories`, `technologies`,
201/// or `keywords` must be set.
202#[derive(Debug, Default, Serialize, Deserialize, Clone)]
203pub struct DomainAnalyticsApiTechnologiesSummaryPost {
204    /// Target technology paths (`$group_id.$category_id`), max 10.
205    #[serde(skip_serializing_if = "Option::is_none")]
206    pub technology_paths: Option<Vec<DomainAnalyticsApiTechnologyPath>>,
207    /// Target technology group IDs, max 10.
208    #[serde(skip_serializing_if = "Option::is_none")]
209    pub groups: Option<Vec<String>>,
210    /// Target technology category IDs, max 10.
211    #[serde(skip_serializing_if = "Option::is_none")]
212    pub categories: Option<Vec<String>>,
213    /// Target technology names, max 10.
214    #[serde(skip_serializing_if = "Option::is_none")]
215    pub technologies: Option<Vec<String>>,
216    /// Domain meta keywords to match, max 10.
217    #[serde(skip_serializing_if = "Option::is_none")]
218    pub keywords: Option<Vec<String>>,
219    /// Match mode: `as_is` (exact, default) or `entry` (partial).
220    #[serde(skip_serializing_if = "Option::is_none")]
221    pub mode: Option<String>,
222    /// Result filters, each a `[field, operator, value]` array (max 8).
223    #[serde(skip_serializing_if = "Option::is_none")]
224    pub filters: Option<Vec<Value>>,
225    /// Maximum elements in internal arrays (default 10, max 10000).
226    #[serde(skip_serializing_if = "Option::is_none")]
227    pub internal_list_limit: Option<i32>,
228    /// User-defined task identifier (max 255 characters).
229    #[serde(skip_serializing_if = "Option::is_none")]
230    pub tag: Option<String>,
231}
232
233impl DomainAnalyticsApiTechnologiesSummaryPost {
234    /// Creates an empty request. Set one of the technology or keyword selectors.
235    pub fn new() -> DomainAnalyticsApiTechnologiesSummaryPost {
236        DomainAnalyticsApiTechnologiesSummaryPost::default()
237    }
238}
239
240/// Request body for the `technology_stats` endpoint.
241#[derive(Debug, Default, Serialize, Deserialize, Clone)]
242pub struct DomainAnalyticsApiTechnologyStatsPost {
243    /// Target technology name (e.g. `WordPress`).
244    pub technology: String,
245    /// Start date of the range (`yyyy-mm-dd`, minimum `2022-10-31`).
246    #[serde(skip_serializing_if = "Option::is_none")]
247    pub date_from: Option<String>,
248    /// End date of the range (`yyyy-mm-dd`, defaults to today).
249    #[serde(skip_serializing_if = "Option::is_none")]
250    pub date_to: Option<String>,
251    /// User-defined task identifier (max 255 characters).
252    #[serde(skip_serializing_if = "Option::is_none")]
253    pub tag: Option<String>,
254}
255
256impl DomainAnalyticsApiTechnologyStatsPost {
257    /// Creates a request for the given technology name.
258    pub fn new(technology: String) -> DomainAnalyticsApiTechnologyStatsPost {
259        DomainAnalyticsApiTechnologyStatsPost {
260            technology,
261            ..Default::default()
262        }
263    }
264}
265
266/// Request body for the `domains_by_technology` endpoint.
267///
268/// At least one of `technologies`, `technology_paths`, `groups`, `categories`,
269/// or `keywords` must be set.
270#[derive(Debug, Default, Serialize, Deserialize, Clone)]
271pub struct DomainAnalyticsApiDomainsByTechnologyPost {
272    /// Target technology names, max 10.
273    #[serde(skip_serializing_if = "Option::is_none")]
274    pub technologies: Option<Vec<String>>,
275    /// Target technology paths (`$group_id.$category_id`), max 10.
276    #[serde(skip_serializing_if = "Option::is_none")]
277    pub technology_paths: Option<Vec<DomainAnalyticsApiTechnologyPath>>,
278    /// Target technology group IDs, max 10.
279    #[serde(skip_serializing_if = "Option::is_none")]
280    pub groups: Option<Vec<String>>,
281    /// Target technology category IDs, max 10.
282    #[serde(skip_serializing_if = "Option::is_none")]
283    pub categories: Option<Vec<String>>,
284    /// Domain meta keywords to match, max 10.
285    #[serde(skip_serializing_if = "Option::is_none")]
286    pub keywords: Option<Vec<String>>,
287    /// Match mode: `as_is` (exact, default) or `entry` (partial).
288    #[serde(skip_serializing_if = "Option::is_none")]
289    pub mode: Option<String>,
290    /// Result filters, each a `[field, operator, value]` array (max 8).
291    #[serde(skip_serializing_if = "Option::is_none")]
292    pub filters: Option<Vec<Value>>,
293    /// Sorting rules such as `["domain_rank,desc"]` (max 3).
294    #[serde(skip_serializing_if = "Option::is_none")]
295    pub order_by: Option<Vec<String>>,
296    /// Maximum number of returned domains (default 100, max 10000).
297    #[serde(skip_serializing_if = "Option::is_none")]
298    pub limit: Option<i32>,
299    /// Offset in the results array (default 0, max 9999).
300    #[serde(skip_serializing_if = "Option::is_none")]
301    pub offset: Option<i32>,
302    /// Pagination token for fetching results beyond the offset limit.
303    #[serde(skip_serializing_if = "Option::is_none")]
304    pub offset_token: Option<String>,
305    /// User-defined task identifier (max 255 characters).
306    #[serde(skip_serializing_if = "Option::is_none")]
307    pub tag: Option<String>,
308}
309
310impl DomainAnalyticsApiDomainsByTechnologyPost {
311    /// Creates a request for the given technology names.
312    pub fn new(technologies: Vec<String>) -> DomainAnalyticsApiDomainsByTechnologyPost {
313        DomainAnalyticsApiDomainsByTechnologyPost {
314            technologies: Some(technologies),
315            ..Default::default()
316        }
317    }
318}
319
320/// Request body for the `domains_by_html_terms` endpoint.
321#[derive(Debug, Default, Serialize, Deserialize, Clone)]
322pub struct DomainAnalyticsApiDomainsByHtmlTermsPost {
323    /// HTML elements, tags, or attributes to search for, max 10.
324    pub search_terms: Vec<String>,
325    /// Domain meta keywords to match, max 10.
326    #[serde(skip_serializing_if = "Option::is_none")]
327    pub keywords: Option<Vec<String>>,
328    /// Match mode: `entry` (default) or `strict_entry`.
329    #[serde(skip_serializing_if = "Option::is_none")]
330    pub mode: Option<String>,
331    /// Result filters, each a `[field, operator, value]` array (max 8).
332    #[serde(skip_serializing_if = "Option::is_none")]
333    pub filters: Option<Vec<Value>>,
334    /// Sorting rules such as `["domain_rank,desc"]` (max 3).
335    #[serde(skip_serializing_if = "Option::is_none")]
336    pub order_by: Option<Vec<String>>,
337    /// Maximum number of returned domains (default 100, max 10000).
338    #[serde(skip_serializing_if = "Option::is_none")]
339    pub limit: Option<i32>,
340    /// Offset in the results array (default 0, max 9999).
341    #[serde(skip_serializing_if = "Option::is_none")]
342    pub offset: Option<i32>,
343    /// Pagination token for fetching results beyond the offset limit.
344    #[serde(skip_serializing_if = "Option::is_none")]
345    pub offset_token: Option<String>,
346    /// User-defined task identifier (max 255 characters).
347    #[serde(skip_serializing_if = "Option::is_none")]
348    pub tag: Option<String>,
349}
350
351impl DomainAnalyticsApiDomainsByHtmlTermsPost {
352    /// Creates a request for the given HTML search terms (max 10).
353    pub fn new(search_terms: Vec<String>) -> DomainAnalyticsApiDomainsByHtmlTermsPost {
354        DomainAnalyticsApiDomainsByHtmlTermsPost {
355            search_terms,
356            ..Default::default()
357        }
358    }
359}
360
361/// Request body for the `domain_technologies` endpoint.
362#[derive(Debug, Default, Serialize, Deserialize, Clone)]
363pub struct DomainAnalyticsApiDomainTechnologiesPost {
364    /// Target domain name to analyze.
365    pub target: String,
366    /// User-defined task identifier (max 255 characters).
367    #[serde(skip_serializing_if = "Option::is_none")]
368    pub tag: Option<String>,
369}
370
371impl DomainAnalyticsApiDomainTechnologiesPost {
372    /// Creates a request for the given target domain.
373    pub fn new(target: String) -> DomainAnalyticsApiDomainTechnologiesPost {
374        DomainAnalyticsApiDomainTechnologiesPost {
375            target,
376            ..Default::default()
377        }
378    }
379}