Help! getElementPropertyValue() is ignoring my response headers in Katalon?

Hey everyone,

I’m pretty new to API testing in Katalon Studio and I’ve been stuck on this for the last few hours. I’m trying to test a login/registration API where the server sends a dynamic Authorization token back, but it’s hidden inside the Response Header, not the actual JSON body.

I looked up some tutorials and saw everyone using WS.getElementPropertyValue(). I tried to use it like this:

Groovy

def response = WS.sendRequest(findTestObject('Object Repository/LoginRequest'))
def token = WS.getElementPropertyValue(response, 'Authorization')

But every time I run it, it just returns null. I print out the response.getResponseBodyContent() and I can see the body is just a simple {"status": "success"} message. The token is definitely in the headers (I checked it in Postman), but it seems like getElementPropertyValue completely ignores the headers and only looks at the JSON body!

How do I actually grab a specific key from the header list? Do I need to write custom Java/Groovy code for this, or is there a built-in way I’m missing? Any help or code snippets would be life-saving!

Problem Analysis

You’ve correctly identified the issue: WS.getElementPropertyValue() is designed exclusively for parsing the response body (JSON/XML), not HTTP headers. Headers and body are separate concerns in HTTP responses, and Katalon provides different methods to access each.

The reason your code returns null is that getElementPropertyValue() searches the JSON body structure, not the HTTP header metadata. Since your Authorization token is in the response headers, this method will never find it.

Solution

Use response.getHeaderFields() to extract headers as a Map:

import com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords as WS

// 1. Send the request
def response = WS.sendRequest(findTestObject('Object Repository/LoginRequest'))

// 2. Verify status code first
WS.verifyResponseStatusCode(response, 200)

// 3. Extract headers as a Map
Map headerFields = response.getHeaderFields()

// 4. Get the Authorization token from headers
def token = headerFields.get('Authorization')

// 5. Print for verification
println("Token: " + token)

// 6. Store in a variable for use in subsequent requests
GlobalVariable.authToken = token

Alternative approach with null checking:

def response = WS.sendRequest(findTestObject('Object Repository/LoginRequest'))
WS.verifyResponseStatusCode(response, 200)

Map headerFields = response.getHeaderFields()

// Handle case-sensitivity and null values
def token = headerFields.get('Authorization') ?: headerFields.get('authorization')

if (token != null) {
    println("Successfully extracted token: " + token)
    GlobalVariable.authToken = token
} else {
    println("ERROR: Authorization header not found!")
    println("Available headers: " + headerFields.keySet())
}

Key Considerations

1. Header Name Case Sensitivity
HTTP headers are technically case-insensitive, but Java’s Map is case-sensitive. If headerFields.get('Authorization') returns null, try lowercase: headerFields.get('authorization'). You can also print all available headers to debug:

println("All headers: " + headerFields.keySet())

2. Using the Token in Subsequent Requests
Once extracted, use the token in your next API request by setting it as a header:

// In your next API request's HTTP Header tab, set:
// Authorization: ${authToken}

// Or programmatically:
def nextRequest = findTestObject('Object Repository/NextRequest')
nextRequest.setHttpHeader('Authorization', GlobalVariable.authToken)
def nextResponse = WS.sendRequest(nextRequest)

3. Response Header vs. Response Body

  • Headers (use getHeaderFields()): Authorization, Content-Type, Set-Cookie, Location, etc.
  • Body (use getElementPropertyValue()): JSON/XML data like {"status": "success"}

4. Best Practice for API Testing
According to Katalon’s official best practices, always verify both status code AND headers:

def response = WS.sendRequest(findTestObject('LoginRequest'))

// Verify status
WS.verifyResponseStatusCode(response, 200)

// Verify Content-Type header
Map headers = response.getHeaderFields()
WS.verifyElementPropertyValue(response, 'Content-Type', 'application/json')

References

In enterprise-level API test automation, hardcoding header extraction in every test case introduces technical debt. The cleanest, most scalable approach is to abstract this logic into a Custom Keyword. This keeps your test scripts clean, readable, and reusable across your entire test suite.

Step 1: Create a Custom Keyword

Create a new Keyword package (e.g., com.helper.api) and define a helper function to safely extract header values.

Groovy

package com.helper.api

import com.kms.katalon.core.annotation.Keyword
import com.kms.katalon.core.testobject.ResponseObject
import com.kms.katalon.core.util.KeywordUtil

public class ApiHelper {

    /**
     * Extracts a specific header value from a ResponseObject.
     * @param response The ResponseObject returned by WS.sendRequest()
     * @param headerName The name of the header to retrieve (case-insensitive)
     * @return The header value string, or null if not found
     */
    @Keyword
    def static String getHeaderValue(ResponseObject response, String headerName) {
        // Retrieve all headers as a Map<String, String> or Map<String, List<String>>
        def headers = response.getHeaderFields()
        
        if (headers == null) {
            KeywordUtil.logInfo("No headers found in the response.")
            return null
        }
        
        // Find the key case-insensitively to prevent typos (e.g., 'authorization' vs 'Authorization')
        def matchingKey = headers.keySet().find { it.equalsIgnoreCase(headerName) }
        
        if (matchingKey) {
            // Header fields can contain a list of values; grab the first one
            def value = headers.get(matchingKey)[0]
            KeywordUtil.logInfo("Successfully extracted header [${headerName}]: ${value}")
            return value
        }
        
        KeywordUtil.markWarning("Header [${headerName}] not found in the response.")
        return null
    }
}

Step 2: Use the Keyword in your Test Script

Now, your Manual or Script view remains incredibly streamlined and readable:

Groovy

import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject
import com.kms.katalon.core.testobject.ResponseObject
import com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords as WS

// 1. Send the API request
ResponseObject response = WS.sendRequest(findTestObject('Object Repository/LoginRequest'))

// 2. Call your custom keyword to parse the header safely
String authToken = CustomKeywords.'com.helper.api.ApiHelper.getHeaderValue'(response, 'Authorization')

// 3. Verify or use the token in subsequent requests
WS.verifyLessThanOrEqual(response.getStatusCode(), 201)
assert authToken != null

The problem: WS.getElementPropertyValue() only parses the response body (JSON/XML), not HTTP headers. Since your Authorization token is in the response headers, this method will never find it.

Solution: Use response.getHeaderFields() Instead

**import com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords as WS

// 1. Send the request
def response = WS.sendRequest(findTestObject('Object Repository/LoginRequest'))

// 2. Verify status code first
WS.verifyResponseStatusCode(response, 200)

// 3. Extract headers as a Map
Map headerFields = response.getHeaderFields()

// 4. Get the Authorization token from headers
def token = headerFields.get('Authorization')

// 5. Print for verification
println("Token: " + token)

// 6. Store in GlobalVariable for use in subsequent requests
GlobalVariable.authToken = token**

Alternative: Handle Case Sensitivity + Null Checking

**def response = WS.sendRequest(findTestObject('Object Repository/LoginRequest'))
WS.verifyResponseStatusCode(response, 200)

Map headerFields = response.getHeaderFields()

// Handle case-insensitivity (HTTP headers are case-insensitive, but Java Map is case-sensitive)
def token = headerFields.get('Authorization') ?: headerFields.get('authorization')

if (token != null) {
println("Successfully extracted token: " + token)
GlobalVariable.authToken = token
} else {
println("ERROR: Authorization header not found!")
println("Available headers: " + headerFields.keySet()) // Debug: see all headers
}

Key Differences: Headers vs Body

What You Need Method to Use Example
Response Headers response.getHeaderFields() Authorization, Content-Type, Set-Cookie, Location
Response Body (JSON/XML) WS.getElementPropertyValue() {"status": "success"}, nested JSON data

Using the Token in Subsequent Requests

Once extracted, use the token in your next API request:

// Option 1: In Test Object HTTP Header tab**
// Set: Authorization: ${authToken}

// Option 2: Programmatically
def nextRequest = findTestObject('Object Repository/NextRequest')
nextRequest.setHttpHeader('Authorization', GlobalVariable.authToken)
def nextResponse = WS.sendRequest(nextRequest)**

Debug Tip: Print All Headers

If Authorization returns null, debug by printing all available headers:


**`println("All headers: " + headerFields.keySet())`**

This helps you see the exact header name (it might be `authorization` lowercase or something else).

**Bottom line:** Use `getHeaderFields()` for headers, `getElementPropertyValue()` for body—they're separate concerns in HTTP responses

did you check logs?

WS.getElementPropertyValue() only parses the JSON/XML body, so it will always return null for headers. Use response.getHeaderFields() instead

def response = WS.sendRequest(findTestObject('Object Repository/LoginRequest'))
Map<String, List<String>> headers = response.getHeaderFields()
def token = headers.get('Authorization')?.get(0)

note that getHeaderFields() returns a Map<String, List<String>> and the keys are case-sensitive, so if you get null, try lowercase 'authorization' or print headers.keySet() to see the exact key name the server is using

Please check the solutions above and let us know.