> Portal Navigation:
> 
> - Append `.md` to any URL under `https://dev.wix.com/docs/` to get its markdown version.
> - Pages are either content pages (article or reference text) or menu pages (a list of links to child pages).
> - To get a menu page, truncate any URL to a parent path and append `.md` (e.g. `https://dev.wix.com/docs/sdk.md`, `https://dev.wix.com/docs/sdk/core-modules.md`).
> - Top-level index of all portals: https://dev.wix.com/docs/llms.txt
> - Full concatenated docs: https://dev.wix.com/docs/llms-full.txt

# BulkUpdateKeywordResearchItems

# Package: seo

# Namespace: KeywordResearchServiceV1

# Method link: https://dev.wix.com/docs/api-reference/business-management/seo/content-plan-keyword-research-v1/bulk-update-keyword-research-items.md

## Permission Scopes:
Manage SEO Settings: SCOPE.PROMOTE.MANAGE-SEO

## Introduction

Updates multiple keyword research items.

This method has no field mask and writes every field present on each
entry. `keyword` and `mainKeyword` remain the only writable fields, and
`mainKeyword` only promotes, as it does for a single item. Repeating an
item ID within one call is rejected.

Validation runs across the whole request before anything is written, so a
problem rejects the entire call rather than failing one entry. Every
returned entry therefore reports success.

A keyword research holds at most 30 keywords, counted after the update.
That limit is reached well before the request's own item limit.

This method copies AI-generated research the same way a single-item
update does, so send the `keywordResearchId` from the response on your
next write. Edits don't survive a later generation.

To update a single keyword research item, call
[Update Keyword Research Item](https://dev.wix.com/docs/api-reference/business-management/seo/content-plan-keyword-research-v1/update-keyword-research-item.md).

---

## REST API

### Schema

```
 Method: bulkUpdateKeywordResearchItems
 Description: Updates multiple keyword research items.  This method has no field mask and writes every field present on each entry. `keyword` and `mainKeyword` remain the only writable fields, and `mainKeyword` only promotes, as it does for a single item. Repeating an item GUID within one call is rejected.  Validation runs across the whole request before anything is written, so a problem rejects the entire call rather than failing one entry. Every returned entry therefore reports success.  A keyword research holds at most 30 keywords, counted after the update. That limit is reached well before the request's own item limit.  This method copies AI-generated research the same way a single-item update does, so send the `keywordResearchId` from the response on your next write. Edits don't survive a later generation.  To update a single keyword research item, call [Update Keyword Research Item](https://dev.wix.com/docs/api-reference/business-management/seo/content-plan-keyword-research-v1/update-keyword-research-item.md).
 URL: https://www.wixapis.com/promote/seo/v1/bulk/keyword-research-items/update
 Method: POST
 # Note: If the parameter `a.b` is listed under required parameters, `b` is only required if `a` is also present.
 Required parameters:  keywordResearchId
 Method parameters: 
   param name: items | type: array<items> | description: Keyword research items to update.  Each item GUID must appear at most once. The research holds at most 30 keywords once the update is applied.  | validation: minItems 1, maxItems 1000
              - name: id | type: string | description: GUID of the keyword research item to update.  | validation: format GUID
              - name: keyword | type: string | description: New keyword.  Rejected if it's longer than 80 characters, or if it duplicates another keyword in the same research. Changing it also refreshes the item's `searchVolume` and `competition`.  | validation: maxLength 1000
              - name: mainKeyword | type: boolean | description: Whether to make this item its page's main keyword.  Set to `true` to promote it. `false` and omitting the field both leave the current main keyword unchanged, so this field can't demote one.  
   param name: keywordResearchId | type: keywordResearchId | description: GUID of the keyword research the items belong to.  Use the `keywordResearchId` from your most recent read or write. | required: true | validation: format GUID
 Return type: BulkUpdateKeywordResearchItemsResponse
  - name: results | type: array<BulkKeywordResearchItemResult> | description: Result for each entry, correlated by `itemMetadata.originalIndex`.  | validation: maxItems 1000
     - name: itemMetadata | type: ItemMetadata | description: Success/failure and error detail for this entry.  
        - name: id | type: string | description: Item GUID. Should always be available, unless it's impossible (for example, when failing to create an item).  | validation: maxLength 100
        - name: originalIndex | type: integer | description: Index of the item within the request array. Allows for correlation between request and response items.  
        - name: success | type: boolean | description: Whether the requested action was successful for this item. When `false`, the `error` field is populated.  
        - name: error | type: ApplicationError | description: Details about the error in case of failure.  
           - name: code | type: string | description: Error code.  
           - name: description | type: string | description: Description of the error.  
           - name: data | type: object | description: Data related to the error.  
  - name: bulkActionMetadata | type: BulkActionMetadata | description: How many entries succeeded and how many failed.  
     - name: totalSuccesses | type: integer | description: Number of items that were successfully processed.  
     - name: totalFailures | type: integer | description: Number of items that couldn't be processed.  
     - name: undetailedFailures | type: integer | description: Number of failures without details because detailed failure threshold was exceeded.  
  - name: keywordResearchItems | type: array<KeywordResearch> | description: The full set of keyword research items after the update.  | validation: maxItems 1000
     - name: id | type: string | description: Keyword research item GUID.  | read-only: true | validation: format GUID
     - name: keyword | type: string | description: The keyword itself.  An update is rejected if the new keyword is longer than 80 characters, or if it duplicates another keyword in the same research.  | validation: maxLength 1000
     - name: pageId | type: string | description: GUID of the site page the keyword is assigned to.  | validation: maxLength 1000
     - name: itemType | type: string | description: Type of the site page the keyword is assigned to, such as a static page or a blog post.  | validation: maxLength 1000
     - name: pageUrl | type: string | description: URL of the site page the keyword is assigned to.  | validation: maxLength 1000
     - name: competition | type: integer | description: How hard it is to rank for the keyword, on a scale where a higher number means more competition.  Recalculated when `keyword` changes, even if you don't name this field in the field mask.  | validation: format int32
     - name: searchVolume | type: integer | description: Estimated number of searches for the keyword per month.  Recalculated when `keyword` changes, even if you don't name this field in the field mask.  | validation: format int32
     - name: pageDeleted | type: boolean | description: Whether the site page this keyword is assigned to has been deleted.  A keyword assigned to a deleted page stays in the research.  
     - name: primary | type: boolean | description: Whether this keyword is the main keyword for its page.  A page has a single main keyword, and the other keywords in its cluster support it.  
     - name: clusterName | type: string | description: Name of the cluster that groups this keyword with the others covering the same topic.  | validation: maxLength 1000
  - name: keywordResearchId | type: string | description: GUID of the keyword research holding the updated items.  This can differ from the GUID you sent, because the first edit to generated research copies it. Use this value for your next write.  | validation: format GUID
  - name: mainKeywordMap | type: object | description: GUID of the main keyword for each page, keyed by page GUID.  | validation: format map


```

### Examples

### Update several keywords in one call
Validation runs across the whole request before anything is written, so every returned entry reports success. Each item ID may appear only once.

```curl
curl -X POST \
'https://www.wixapis.com/seo-content-plan-service/v1/bulk/keyword-research-items/update' \
-H 'Authorization: <AUTH>' \
-H 'Content-Type: application/json' \
-d '{
  "keywordResearchId": "3f9c2b71-4d8e-4a15-9c63-b0e7d21a5f84",
  "items": [
    {
      "id": "b70d5a92-31ef-4c08-8a6d-45f19be7c203",
      "keyword": "how to store coffee beans at home"
    },
    {
      "id": "8c14e7d0-2a63-4b9f-91d5-7ae0c3f28b64",
      "mainKeyword": true
    }
  ]
}'
```

---

## JavaScript SDK

### Schema

```
 Method: wixClientAdmin.seo.keywordResearch.bulkUpdateKeywordResearchItems(keywordResearchId, options)
 Description: Updates multiple keyword research items.  This method has no field mask and writes every field present on each entry. `keyword` and `mainKeyword` remain the only writable fields, and `mainKeyword` only promotes, as it does for a single item. Repeating an item GUID within one call is rejected.  Validation runs across the whole request before anything is written, so a problem rejects the entire call rather than failing one entry. Every returned entry therefore reports success.  A keyword research holds at most 30 keywords, counted after the update. That limit is reached well before the request's own item limit.  This method copies AI-generated research the same way a single-item update does, so send the `keywordResearchId` from the response on your next write. Edits don't survive a later generation.  To update a single keyword research item, call [Update Keyword Research Item](https://dev.wix.com/docs/api-reference/business-management/seo/content-plan-keyword-research-v1/update-keyword-research-item.md).
 # Note: If the parameter `a.b` is listed under required parameters, `b` is only required if `a` is also present.
 Required parameters:  keywordResearchId
 Method parameters: 
   param name: keywordResearchId | type: string | description: GUID of the keyword research the items belong to.  Use the `keywordResearchId` from your most recent read or write. | required: true | validation: format GUID
   param name: options | type: BulkUpdateKeywordResearchItemsOptions  none  
        - name: items | type: array<UpdatedKeywordResearch> | description: Keyword research items to update.  Each item GUID must appear at most once. The research holds at most 30 keywords once the update is applied.  | validation: minItems 1, maxItems 1000
           - name: _id | type: string | description: GUID of the keyword research item to update.  | validation: format GUID
           - name: keyword | type: string | description: New keyword.  Rejected if it's longer than 80 characters, or if it duplicates another keyword in the same research. Changing it also refreshes the item's `searchVolume` and `competition`.  | validation: maxLength 1000
           - name: mainKeyword | type: boolean | description: Whether to make this item its page's main keyword.  Set to `true` to promote it. `false` and omitting the field both leave the current main keyword unchanged, so this field can't demote one.  
 Return type: PROMISE<BulkUpdateKeywordResearchItemsResponse>
  - name: results | type: array<BulkKeywordResearchItemResult> | description: Result for each entry, correlated by `itemMetadata.originalIndex`.  | validation: maxItems 1000
     - name: itemMetadata | type: ItemMetadata | description: Success/failure and error detail for this entry.  
        - name: _id | type: string | description: Item GUID. Should always be available, unless it's impossible (for example, when failing to create an item).  | validation: maxLength 100
        - name: originalIndex | type: integer | description: Index of the item within the request array. Allows for correlation between request and response items.  
        - name: success | type: boolean | description: Whether the requested action was successful for this item. When `false`, the `error` field is populated.  
        - name: error | type: ApplicationError | description: Details about the error in case of failure.  
           - name: code | type: string | description: Error code.  
           - name: description | type: string | description: Description of the error.  
           - name: data | type: object | description: Data related to the error.  
  - name: bulkActionMetadata | type: BulkActionMetadata | description: How many entries succeeded and how many failed.  
     - name: totalSuccesses | type: integer | description: Number of items that were successfully processed.  
     - name: totalFailures | type: integer | description: Number of items that couldn't be processed.  
     - name: undetailedFailures | type: integer | description: Number of failures without details because detailed failure threshold was exceeded.  
  - name: keywordResearchItems | type: array<KeywordResearch> | description: The full set of keyword research items after the update.  | validation: maxItems 1000
     - name: _id | type: string | description: Keyword research item GUID.  | read-only: true | validation: format GUID
     - name: keyword | type: string | description: The keyword itself.  An update is rejected if the new keyword is longer than 80 characters, or if it duplicates another keyword in the same research.  | validation: maxLength 1000
     - name: pageId | type: string | description: GUID of the site page the keyword is assigned to.  | validation: maxLength 1000
     - name: itemType | type: string | description: Type of the site page the keyword is assigned to, such as a static page or a blog post.  | validation: maxLength 1000
     - name: pageUrl | type: string | description: URL of the site page the keyword is assigned to.  | validation: maxLength 1000
     - name: competition | type: integer | description: How hard it is to rank for the keyword, on a scale where a higher number means more competition.  Recalculated when `keyword` changes, even if you don't name this field in the field mask.  | validation: format int32
     - name: searchVolume | type: integer | description: Estimated number of searches for the keyword per month.  Recalculated when `keyword` changes, even if you don't name this field in the field mask.  | validation: format int32
     - name: pageDeleted | type: boolean | description: Whether the site page this keyword is assigned to has been deleted.  A keyword assigned to a deleted page stays in the research.  
     - name: primary | type: boolean | description: Whether this keyword is the main keyword for its page.  A page has a single main keyword, and the other keywords in its cluster support it.  
     - name: clusterName | type: string | description: Name of the cluster that groups this keyword with the others covering the same topic.  | validation: maxLength 1000
  - name: keywordResearchId | type: string | description: GUID of the keyword research holding the updated items.  This can differ from the GUID you sent, because the first edit to generated research copies it. Use this value for your next write.  | validation: format GUID
  - name: mainKeywordMap | type: object | description: GUID of the main keyword for each page, keyed by page GUID.  | validation: format map


```

### Examples

### Update several keywords in one call
There's no field mask here, so every field present on an entry is written. Validation runs across the whole request before anything is saved, so a problem rejects the entire call rather than failing one entry.

```javascript
import { keywordResearch } from "@wix/seo";

async function bulkUpdateKeywordResearchItems() {
  const response = await keywordResearch.bulkUpdateKeywordResearchItems(
    "8f3b6d2e-4c17-4a90-b5e3-9d70c1af2b48",
    {
      items: [
        {
          _id: "c5f9e1a4-7b62-4d18-9a35-1e8f4c2d6b70",
          keyword: "hand thrown ceramic mugs",
          mainKeyword: true,
        },
        {
          _id: "d7a341c4-196b-46e7-813c-2b0fc1847ec6",
          keyword: "glazed stoneware mug set",
        },
      ],
    },
  );
}

/* Promise resolves to:
 * {
 *   "results": [
 *     {
 *       "itemMetadata": {
 *         "id": "c5f9e1a4-7b62-4d18-9a35-1e8f4c2d6b70",
 *         "originalIndex": 0,
 *         "success": true
 *       }
 *     },
 *     {
 *       "itemMetadata": {
 *         "id": "d7a341c4-196b-46e7-813c-2b0fc1847ec6",
 *         "originalIndex": 1,
 *         "success": true
 *       }
 *     }
 *   ],
 *   "bulkActionMetadata": {
 *     "totalSuccesses": 2,
 *     "totalFailures": 0,
 *     "undetailedFailures": 0
 *   },
 *   "keywordResearchItems": [
 *     {
 *       "_id": "c5f9e1a4-7b62-4d18-9a35-1e8f4c2d6b70",
 *       "keyword": "hand thrown ceramic mugs",
 *       "pageId": "a1b2c3d4-e5f6-4890-abcd-ef1234567890",
 *       "itemType": "STATIC_PAGE",
 *       "pageUrl": "https://example.com/shop",
 *       "competition": 28,
 *       "searchVolume": 1300,
 *       "pageDeleted": false,
 *       "primary": true,
 *       "clusterName": "ceramic drinkware"
 *     },
 *     {
 *       "_id": "d7a341c4-196b-46e7-813c-2b0fc1847ec6",
 *       "keyword": "glazed stoneware mug set",
 *       "pageId": "a1b2c3d4-e5f6-4890-abcd-ef1234567890",
 *       "itemType": "STATIC_PAGE",
 *       "pageUrl": "https://example.com/shop",
 *       "competition": 19,
 *       "searchVolume": 320,
 *       "pageDeleted": false,
 *       "primary": false,
 *       "clusterName": "ceramic drinkware"
 *     }
 *   ],
 *   "keywordResearchId": "b2c4e8a0-5f31-4276-9c8d-3a1e7b90fd52",
 *   "mainKeywordMap": {
 *     "a1b2c3d4-e5f6-4890-abcd-ef1234567890": "c5f9e1a4-7b62-4d18-9a35-1e8f4c2d6b70"
 *   }
 * }
 */

```

### bulkUpdateKeywordResearchItems (self-hosted)
Self-hosted SDK calls require you to [create a client](https://dev.wix.com/docs/sdk/articles/work-with-the-sdk/about-the-wix-client.md).

```javascript
import { createClient } from '@wix/sdk';
import { keywordResearch } from '@wix/seo';
// Import the auth strategy for the relevant access type
// Import the relevant host module if needed

const myWixClient = createClient ({
  modules: { keywordResearch },
  // Include the auth strategy and host as relevant
});


async function bulkUpdateKeywordResearchItems(keywordResearchId,options) {
  const response = await myWixClient.keywordResearch.bulkUpdateKeywordResearchItems(keywordResearchId,options);
};
```

---