Skip to main content
October 13, 2025
Question

Logging Interface Access

  • October 13, 2025
  • 20 replies
  • 0 views

I hope this message finds you well.

I would like to log the event of an interface being opened.
However, my understanding is that on the interface itself, unless an action such as clicking a button occurs,

it is not possible to write a record or start a process model.

When consulting ChatGPT, I received the following idea:

  1. Create a Web API on Appian that returns an image as the response and simultaneously saves a log.
  2. Place an image on the target interface and set the endpoint of the Web API created in (1) as the image source.
  3. As a result, when the interface is opened, the Web API in (1) is called, and the log is recorded.

However, it seems that the function a!writeToDataStoreEntity does not get triggered inside the Web API.

I have two questions and would appreciate your advice:

  1. What should I review to implement the above ChatGPT idea successfully?
  2. Are there alternative methods to log when an interface is opened?

Thank you in advance for your kind advice.

    20 replies

    stefanhelzle0001
    October 13, 2025

    ChatGPT has no clue how Appian works.

    Did you check whether the records usage log meets your requirements?

    October 13, 2025

    ChatGPT's approach isn't "wrong", it's just incomplete and can be misleading. Even 2025's latest LLMs are like the over-confident interns we're constantly correcting and rolling our eyes at. Yet in this case, its approach is possible.

    For this to work

    • You need a what's colloquially known as a "loopback" API call, where an Appian API is called via an Appian integration that uses an API key from the admin console. In theory it's possible to have the logged in user authenticate to the Appian API as themselves, but in practice it's a little more nuanced than that. Depending on your environment's security requirements, loopback API's may not be a good idea to do in production.
    • API trace logging must be enabled in the admin console. Enabling this logging can cause a bit of overhead in production, and the logs will be overwritten every few days (or ~10MB) if there is a large volume of API calls.
    • View perflogs/web_api_trace.csv

    According to your prompt, you don't need to know who loaded the page, just that the page was loaded. If you need to know who loaded the page, there's a bit more development / complexity there.

    mikes0011
    Brainy
    October 13, 2025

    If you absolutely must have this, it's pretty easy to create an Appian Web API that accepts key info (i.e. the username of the current user, and the name or some sort of identifier for the interface in question), which you can then call from the interface at load time in a local variable declaraion calling an Integration.  The API would simply launch a process model that quickly makes an entry for that username and that identifier in a DB table you have previously created, as well as a "loaded at" timestamp. 

    I've implemented something like this for myself and decided to limit the DB table to 1 row per user per day per interface, so when it launches for a particular user, if there's already a row for that date/user/interface, it updates the existing row (incrementing an "updated" timestamp, as well as a "counter" that starts at 1 and increments for every unique load by that user).  This is slightly extra work of course but has been pretty useful to me and our management team in tracking overall site usage.

    October 14, 2025

    Thank you all for your advice.

    Although I initially lacked some information, ultimately, I would like to calculate usage rates for each application from the log data. Therefore, I prefer to save the logs as records rather than text files. Additionally, since I need to calculate usage rates by organization, user information is also necessary.

    Hence, I believe the approach Mike has already implemented is the closest to what I need.

    I implemented the Web API as shown below. While it returns an image file as the response, it seems that neither a!startProcess, a!writeToDataStoreEntity, nor a!writeRecords functions are executing.

    I implemented it using the GET method to return the image file. Is there anything else I should do?


    a!localVariables(

      local!codea: 200,
      local!codeb: 200,
      local!codec: 200,

      local!a: a!writeToDataStoreEntity(
        dataStoreEntity: cons!XLOG_EVENT,
        valueToStore: 'type!{urn:com:appian:types:XLOG}XLOG_RT_EVENT'(
          timestamp: now(),
          appName: "Application Name",
          functionName: "Function Name",
          user: tostring(loggedInUser())
        ),
        onSuccess: a!save(local!codea, 201),
        onError: a!save(local!codea, 202)
      ),

      local!b: a!writeRecords(
        records: 'recordType!{}XLOG rtEvent'(
          'recordType!{}XLOG rtEvent.fields.{}timestamp': now(),
          'recordType!{}XLOG rtEvent.fields.{}appName': "Application Name RT",
          'recordType!{}XLOG rtEvent.fields.{}functionName': "Function Name RT",
          'recordType!{}XLOG rtEvent.fields.{}user': tostring(loggedInUser())
        ),
        onSuccess: a!save(local!codeb, 201),
        onError: a!save(local!codeb, 202)
      ),

      local!c: a!startProcess(
        processModel: cons!XLOG_pmTest,
        onSuccess: a!save(local!codec, 201),
        onError: a!save(local!codec, 202)
      ),

      local!d: a!richTextDisplayField(
        value: "code: " & local!codea & " " & local!codeb& " " & local!codec
      ),

      a!httpResponse(
        statusCode: local!codec,
        headers: {
          a!httpHeader(name: "Content-Type", value: "image/png"),
          a!httpHeader(name: "Cache-Control", value: "no-store, no-cache, must-revalidate, max-age=0"),
          a!httpHeader(name: "Pragma", value: "no-cache")
        },
        body: cons!XLOG_PNG
      )
    )

    NOTE:In this sample code, these local variables are only for debbuging.



    harshas2775
    October 14, 2025

    You web API structure as per this sample code doesnt seem right! the smart servcies should not be related to a local variable. 

    Please check the documentation for steps/considerations. In you use case you can create a web API that has a!startProcess() in it. Whatever you are trying to accomplish in a!writeRecord() and a!writeToDataStoreEntity() should be moved inside the process. 

    The https Response configuration would also come within the onSuccess or onError of a!startProcess() configuration.

    October 14, 2025

    Dear Harsha,

    Thank you for your advice.

    I reviewed the documentation again, modified my code and confirmed that a!startProcess() and a!writeRecord can be executed.

    However, as mentioned in my initial post,
    (1) Create a Web API on Appian that returns an image as the response and simultaneously saves a log.
    (2) Place an image on the target interface and set the endpoint of the Web API created in (1) as the image source.
    (3) As a result, when the interface is opened, the Web API in (1) is called, and the log is recorded.

    Since we intend to implement this behavior, the Web API must be implemented with the GET method.

    As a result, we encountered the error:
    "Smart Services cannot be executed in Web APIs that have a method of 'GET'."

    and cannot proceed further.

    Is there any way to work around this?

    October 14, 2025

    Keizo,

    Create the Web API as a POST but make sure that you check the Queries Data and not Modifies data.

    - The webAPI must create an entry onto the database table where you are logging the event.

    Create an integration to call that webAPI

    In your interface, call the integration

    a!localVariables(

    local!eventLog: rule!MY_Integration(),

    a!sectionLayout(

    label: "My Label",

    contents: {}

    )

    )

    This should work. Let me know if you got any questions

    Lejanson

    October 19, 2025

    Thanks Lejanson.

    >Create the Web API as a POST but make sure that you check the Queries Data and not Modifies data.
    It's very useful for me.